• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-angular / 13331632524

14 Feb 2025 02:51PM CUT coverage: 22.015% (-69.6%) from 91.622%
13331632524

Pull #15372

github

web-flow
Merge d52d57714 into bcb78ae0a
Pull Request #15372: chore(*): test ci passing

1990 of 15592 branches covered (12.76%)

431 of 964 new or added lines in 18 files covered. (44.71%)

19956 existing lines in 307 files now uncovered.

6452 of 29307 relevant lines covered (22.02%)

249.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

38.05
/projects/igniteui-angular/src/lib/core/utils.ts
1
import { CurrencyPipe, formatDate as _formatDate, isPlatformBrowser } from '@angular/common';
2
import { Inject, Injectable, InjectionToken, PLATFORM_ID, inject } from '@angular/core';
3
import { mergeWith } from 'lodash-es';
4
import { NEVER, Observable } from 'rxjs';
5
import { setImmediate } from './setImmediate';
6
import { isDevMode } from '@angular/core';
7
import { IgxTheme } from '../services/theme/theme.token';
8

9
/** @hidden @internal */
10
export const ELEMENTS_TOKEN = /*@__PURE__*/new InjectionToken<boolean>('elements environment');
2✔
11

12
/**
13
 * @hidden
14
 */
15
export const showMessage = (message: string, isMessageShown: boolean): boolean => {
2✔
16
    if (!isMessageShown && isDevMode()) {
×
17
        console.warn(message);
×
18
    }
19

20
    return true;
×
21
};
22

23
export const mkenum = <T extends { [index: string]: U }, U extends string>(x: T) => x;
107✔
24

25
/**
26
 *
27
 * @hidden @internal
28
 */
29
export const getResizeObserver = () => globalThis.window?.ResizeObserver;
339✔
30

31
/**
32
 * @hidden
33
 */
34
export const cloneArray = (array: any[], deep?: boolean) => {
2✔
35
    const arr = [];
42✔
36
    if (!array) {
42!
UNCOV
37
        return arr;
×
38
    }
39
    let i = array.length;
42✔
40
    while (i--) {
42✔
41
        arr[i] = deep ? cloneValue(array[i]) : array[i];
208!
42
    }
43
    return arr;
42✔
44
};
45

46
/**
47
 * Doesn't clone leaf items
48
 *
49
 * @hidden
50
 */
51
export const cloneHierarchicalArray = (array: any[], childDataKey: any): any[] => {
2✔
UNCOV
52
    const result: any[] = [];
×
UNCOV
53
    if (!array) {
×
54
        return result;
×
55
    }
56

UNCOV
57
    for (const item of array) {
×
UNCOV
58
        const clonedItem = cloneValue(item);
×
UNCOV
59
        if (Array.isArray(item[childDataKey])) {
×
UNCOV
60
            clonedItem[childDataKey] = cloneHierarchicalArray(clonedItem[childDataKey], childDataKey);
×
61
        }
UNCOV
62
        result.push(clonedItem);
×
63
    }
UNCOV
64
    return result;
×
65
};
66

67
/**
68
 * Creates an object with prototype from provided source and copies
69
 * all properties descriptors from provided source
70
 * @param obj Source to copy prototype and descriptors from
71
 * @returns New object with cloned prototype and property descriptors
72
 */
73
export const copyDescriptors = (obj) => {
2✔
UNCOV
74
    if (obj) {
×
UNCOV
75
        return Object.create(
×
76
            Object.getPrototypeOf(obj),
77
            Object.getOwnPropertyDescriptors(obj)
78
        );
79
    }
80
}
81

82

83
/**
84
 * Deep clones all first level keys of Obj2 and merges them to Obj1
85
 *
86
 * @param obj1 Object to merge into
87
 * @param obj2 Object to merge from
88
 * @returns Obj1 with merged cloned keys from Obj2
89
 * @hidden
90
 */
91
export const mergeObjects = (obj1: any, obj2: any): any => mergeWith(obj1, obj2, (objValue, srcValue) => {
2✔
UNCOV
92
    if (Array.isArray(srcValue)) {
×
UNCOV
93
        return objValue = srcValue;
×
94
    }
95
});
96

97
/**
98
 * Creates deep clone of provided value.
99
 * Supports primitive values, dates and objects.
100
 * If passed value is array returns shallow copy of the array.
101
 *
102
 * @param value value to clone
103
 * @returns Deep copy of provided value
104
 * @hidden
105
 */
106
export const cloneValue = (value: any): any => {
2✔
UNCOV
107
    if (isDate(value)) {
×
UNCOV
108
        return new Date(value.getTime());
×
109
    }
UNCOV
110
    if (Array.isArray(value)) {
×
UNCOV
111
        return [...value];
×
112
    }
113

UNCOV
114
    if (value instanceof Map || value instanceof Set) {
×
UNCOV
115
        return value;
×
116
    }
117

UNCOV
118
    if (isObject(value)) {
×
UNCOV
119
        const result = {};
×
120

UNCOV
121
        for (const key of Object.keys(value)) {
×
UNCOV
122
            if (key === "externalObject") {
×
123
                continue;
×
124
            }
UNCOV
125
            result[key] = cloneValue(value[key]);
×
126
        }
UNCOV
127
        return result;
×
128
    }
UNCOV
129
    return value;
×
130
};
131

132
/**
133
 * Creates deep clone of provided value.
134
 * Supports primitive values, dates and objects.
135
 * If passed value is array returns shallow copy of the array.
136
 * For Objects property values and references are cached and reused.
137
 * This allows for circular references to same objects.
138
 *
139
 * @param value value to clone
140
 * @param cache map of cached values already parsed
141
 * @returns Deep copy of provided value
142
 * @hidden
143
 */
144
export const cloneValueCached = (value: any, cache: Map<any, any>): any => {
2✔
145
    if (isDate(value)) {
×
146
        return new Date(value.getTime());
×
147
    }
148
    if (Array.isArray(value)) {
×
149
        return [...value];
×
150
    }
151

152
    if (value instanceof Map || value instanceof Set) {
×
153
        return value;
×
154
    }
155

156
    if (isObject(value)) {
×
157
        if (cache.has(value)) {
×
158
            return cache.get(value);
×
159
        }
160

161
        const result = {};
×
162
        cache.set(value, result);
×
163

164
        for (const key of Object.keys(value)) {
×
165
            result[key] = cloneValueCached(value[key], cache);
×
166
        }
167
        return result;
×
168
    }
169
    return value;
×
170
};
171

172
/**
173
 * Parse provided input to Date.
174
 *
175
 * @param value input to parse
176
 * @returns Date if parse succeed or null
177
 * @hidden
178
 */
179
export const parseDate = (value: any): Date | null => {
2✔
180
    // if value is Invalid Date return null
UNCOV
181
    if (isDate(value)) {
×
UNCOV
182
        return !isNaN(value.getTime()) ? value : null;
×
183
    }
UNCOV
184
    return value ? new Date(value) : null;
×
185
};
186

187
/**
188
 * Returns an array with unique dates only.
189
 *
190
 * @param columnValues collection of date values (might be numbers or ISO 8601 strings)
191
 * @returns collection of unique dates.
192
 * @hidden
193
 */
194
export const uniqueDates = (columnValues: any[]) => columnValues.reduce((a, c) => {
2✔
195
    if (!a.cache[c.label]) {
×
196
        a.result.push(c);
×
197
    }
198
    a.cache[c.label] = true;
×
199
    return a;
×
200
}, { result: [], cache: {} }).result;
201

202
/**
203
 * Checks if provided variable is Object
204
 *
205
 * @param value Value to check
206
 * @returns true if provided variable is Object
207
 * @hidden
208
 */
209
export const isObject = (value: any): boolean => !!(value && value.toString() === '[object Object]');
2!
210

211
/**
212
 * Checks if provided variable is Date
213
 *
214
 * @param value Value to check
215
 * @returns true if provided variable is Date
216
 * @hidden
217
 */
218
export const isDate = (value: any): value is Date => {
2✔
219
    return Object.prototype.toString.call(value) === "[object Date]";
14✔
220
}
221

222
/**
223
 * Checks if the two passed arguments are equal
224
 * Currently supports date objects
225
 *
226
 * @param obj1
227
 * @param obj2
228
 * @returns: `boolean`
229
 * @hidden
230
 */
231
export const isEqual = (obj1, obj2): boolean => {
2✔
232
    if (isDate(obj1) && isDate(obj2)) {
2!
UNCOV
233
        return obj1.getTime() === obj2.getTime();
×
234
    }
235
    return obj1 === obj2;
2✔
236
};
237

238
/**
239
 * Utility service taking care of various utility functions such as
240
 * detecting browser features, general cross browser DOM manipulation, etc.
241
 *
242
 * @hidden @internal
243
 */
244
@Injectable({ providedIn: 'root' })
245
export class PlatformUtil {
2✔
246
    public isBrowser: boolean = isPlatformBrowser(this.platformId);
35✔
247
    public isIOS = this.isBrowser && /iPad|iPhone|iPod/.test(navigator.userAgent) && !('MSStream' in window);
35!
248
    public isSafari = this.isBrowser && /Safari[\/\s](\d+\.\d+)/.test(navigator.userAgent);
35✔
249
    public isFirefox = this.isBrowser && /Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent);
35✔
250
    public isEdge = this.isBrowser && /Edge[\/\s](\d+\.\d+)/.test(navigator.userAgent);
35✔
251
    public isChromium = this.isBrowser && (/Chrom|e?ium/g.test(navigator.userAgent) ||
35!
252
        /Google Inc/g.test(navigator.vendor)) && !/Edge/g.test(navigator.userAgent);
253
    public browserVersion = this.isBrowser ? parseFloat(navigator.userAgent.match(/Version\/([\d.]+)/)?.at(1)) : 0;
35!
254

255
    /** @hidden @internal */
256
    public isElements = inject(ELEMENTS_TOKEN, { optional: true });
35✔
257

258
    public KEYMAP = mkenum({
35✔
259
        ENTER: 'Enter',
260
        SPACE: ' ',
261
        ESCAPE: 'Escape',
262
        ARROW_DOWN: 'ArrowDown',
263
        ARROW_UP: 'ArrowUp',
264
        ARROW_LEFT: 'ArrowLeft',
265
        ARROW_RIGHT: 'ArrowRight',
266
        END: 'End',
267
        HOME: 'Home',
268
        PAGE_DOWN: 'PageDown',
269
        PAGE_UP: 'PageUp',
270
        F2: 'F2',
271
        TAB: 'Tab',
272
        SEMICOLON: ';',
273
        // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values#editing_keys
274
        DELETE: 'Delete',
275
        BACKSPACE: 'Backspace',
276
        CONTROL: 'Control',
277
        X: 'x',
278
        Y: 'y',
279
        Z: 'z'
280
    });
281

282
    constructor(@Inject(PLATFORM_ID) private platformId: any) { }
35✔
283

284
    /**
285
     * @hidden @internal
286
     * Returns the actual size of the node content, using Range
287
     * ```typescript
288
     * let range = document.createRange();
289
     * let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
290
     *
291
     * let size = getNodeSizeViaRange(range, column.cells[0].nativeElement);
292
     *
293
     * @remarks
294
     * The last parameter is useful when the size of the element to measure is modified by a
295
     * parent element that has explicit size. In such cases the calculated size is never lower
296
     * and the function may instead remove the parent size while measuring to get the correct value.
297
     * ```
298
     */
299
    public getNodeSizeViaRange(range: Range, node: HTMLElement, sizeHoldingNode?: HTMLElement) {
UNCOV
300
        let overflow = null;
×
301
        let nodeStyles;
302

UNCOV
303
        if (!this.isFirefox) {
×
UNCOV
304
            overflow = node.style.overflow;
×
305
            // we need that hack - otherwise content won't be measured correctly in IE/Edge
UNCOV
306
            node.style.overflow = 'visible';
×
307
        }
308

UNCOV
309
        if (sizeHoldingNode) {
×
UNCOV
310
            const style = sizeHoldingNode.style;
×
UNCOV
311
            nodeStyles = [style.width, style.minWidth, style.flexBasis];
×
UNCOV
312
            style.width = '';
×
UNCOV
313
            style.minWidth = '';
×
UNCOV
314
            style.flexBasis = '';
×
315
        }
316

UNCOV
317
        range.selectNodeContents(node);
×
UNCOV
318
        const scale = node.getBoundingClientRect().width / node.offsetWidth;
×
UNCOV
319
        const width = range.getBoundingClientRect().width / scale;
×
320

UNCOV
321
        if (!this.isFirefox) {
×
322
            // we need that hack - otherwise content won't be measured correctly in IE/Edge
UNCOV
323
            node.style.overflow = overflow;
×
324
        }
325

UNCOV
326
        if (sizeHoldingNode) {
×
UNCOV
327
            sizeHoldingNode.style.width = nodeStyles[0];
×
UNCOV
328
            sizeHoldingNode.style.minWidth = nodeStyles[1];
×
UNCOV
329
            sizeHoldingNode.style.flexBasis = nodeStyles[2];
×
330
        }
331

UNCOV
332
        return width;
×
333
    }
334

335

336
    /**
337
     * Returns true if the current keyboard event is an activation key (Enter/Space bar)
338
     *
339
     * @hidden
340
     * @internal
341
     *
342
     * @memberof PlatformUtil
343
     */
344
    public isActivationKey(event: KeyboardEvent) {
UNCOV
345
        return event.key === this.KEYMAP.ENTER || event.key === this.KEYMAP.SPACE;
×
346
    }
347

348
    /**
349
     * Returns true if the current keyboard event is a combination that closes the filtering UI of the grid. (Escape/Ctrl+Shift+L)
350
     *
351
     * @hidden
352
     * @internal
353
     * @param event
354
     * @memberof PlatformUtil
355
     */
356
    public isFilteringKeyCombo(event: KeyboardEvent) {
UNCOV
357
        return event.key === this.KEYMAP.ESCAPE || (event.ctrlKey && event.shiftKey && event.key.toLowerCase() === 'l');
×
358
    }
359

360
    /**
361
     * @hidden @internal
362
     */
363
    public isLeftClick(event: PointerEvent | MouseEvent) {
UNCOV
364
        return event.button === 0;
×
365
    }
366

367
    /**
368
     * @hidden @internal
369
     */
370
    public isNavigationKey(key: string) {
UNCOV
371
        return [
×
372
            this.KEYMAP.HOME, this.KEYMAP.END, this.KEYMAP.SPACE,
373
            this.KEYMAP.ARROW_DOWN, this.KEYMAP.ARROW_LEFT, this.KEYMAP.ARROW_RIGHT, this.KEYMAP.ARROW_UP
374
        ].includes(key as any);
375
    }
376
}
377

378
/**
379
 * @hidden
380
 */
381
export const flatten = (arr: any[]) => {
2✔
382
    let result = [];
1,690✔
383

384
    arr.forEach(el => {
1,690✔
385
        result.push(el);
1,542✔
386
        if (el.children) {
1,542✔
387
            const children = Array.isArray(el.children) ? el.children : el.children.toArray();
1,414!
388
            result = result.concat(flatten(children));
1,414✔
389
        }
390
    });
391
    return result;
1,690✔
392
};
393

394
export interface CancelableEventArgs {
395
    /**
396
     * Provides the ability to cancel the event.
397
     */
398
    cancel: boolean;
399
}
400

401
export interface IBaseEventArgs {
402
    /**
403
     * Provides reference to the owner component.
404
     */
405
    owner?: any;
406
}
407

408
export interface CancelableBrowserEventArgs extends CancelableEventArgs {
409
    /* blazorSuppress */
410
    /** Browser event */
411
    event?: Event;
412
}
413

414
export interface IBaseCancelableBrowserEventArgs extends CancelableBrowserEventArgs, IBaseEventArgs { }
415

416
export interface IBaseCancelableEventArgs extends CancelableEventArgs, IBaseEventArgs { }
417

418
export const HORIZONTAL_NAV_KEYS = new Set(['arrowleft', 'left', 'arrowright', 'right', 'home', 'end']);
2✔
419

420
export const NAVIGATION_KEYS = new Set([
2✔
421
    'down',
422
    'up',
423
    'left',
424
    'right',
425
    'arrowdown',
426
    'arrowup',
427
    'arrowleft',
428
    'arrowright',
429
    'home',
430
    'end',
431
    'space',
432
    'spacebar',
433
    ' '
434
]);
435
export const ACCORDION_NAVIGATION_KEYS = new Set('up down arrowup arrowdown home end'.split(' '));
2✔
436
export const ROW_EXPAND_KEYS = new Set('right down arrowright arrowdown'.split(' '));
2✔
437
export const ROW_COLLAPSE_KEYS = new Set('left up arrowleft arrowup'.split(' '));
2✔
438
export const ROW_ADD_KEYS = new Set(['+', 'add', '≠', '±', '=']);
2✔
439
export const SUPPORTED_KEYS = new Set([...Array.from(NAVIGATION_KEYS),
2✔
440
...Array.from(ROW_ADD_KEYS), 'enter', 'f2', 'escape', 'esc', 'pagedown', 'pageup']);
441
export const HEADER_KEYS = new Set([...Array.from(NAVIGATION_KEYS), 'escape', 'esc', 'l',
2✔
442
    /** This symbol corresponds to the Alt + L combination under MAC. */
443
    '¬']);
444

445
/**
446
 * @hidden
447
 * @internal
448
 *
449
 * Creates a new ResizeObserver on `target` and returns it as an Observable.
450
 * Run the resizeObservable outside angular zone, because it patches the MutationObserver which causes an infinite loop.
451
 * Related issue: https://github.com/angular/angular/issues/31712
452
 */
453
export const resizeObservable = (target: HTMLElement): Observable<ResizeObserverEntry[]> => {
2✔
454
    const resizeObserver = getResizeObserver();
188✔
455
    // check whether we are on server env or client env
456
    if (resizeObserver) {
188!
457
        return new Observable((observer) => {
188✔
458
                const instance = new resizeObserver((entries: ResizeObserverEntry[]) => {
188✔
459
                    observer.next(entries);
36✔
460
                });
461
                instance.observe(target);
188✔
462
                const unsubscribe = () => instance.disconnect();
188✔
463
                return unsubscribe;
188✔
464
        });
465
    } else {
466
        // if on a server env return a empty observable that does not complete immediately
467
        return NEVER;
×
468
    }
469
}
470

471
/**
472
 * @hidden
473
 * @internal
474
 *
475
 * Compares two maps.
476
 */
477
export const compareMaps = (map1: Map<any, any>, map2: Map<any, any>): boolean => {
2✔
UNCOV
478
    if (!map2) {
×
UNCOV
479
        return !map1 ? true : false;
×
480
    }
UNCOV
481
    if (map1.size !== map2.size) {
×
482
        return false;
×
483
    }
UNCOV
484
    let match = true;
×
UNCOV
485
    const keys = Array.from(map2.keys());
×
UNCOV
486
    for (const key of keys) {
×
UNCOV
487
        if (map1.has(key)) {
×
UNCOV
488
            match = map1.get(key) === map2.get(key);
×
489
        } else {
490
            match = false;
×
491
        }
UNCOV
492
        if (!match) {
×
UNCOV
493
            break;
×
494
        }
495
    }
UNCOV
496
    return match;
×
497
};
498

499
/**
500
 *
501
 * Given a property access path in the format `x.y.z` resolves and returns
502
 * the value of the `z` property in the passed object.
503
 *
504
 * @hidden
505
 * @internal
506
 */
507
export const resolveNestedPath = (obj: any, path: string) => {
2✔
508
    const parts = path?.split('.') ?? [];
3,656✔
509
    let current = obj[parts.shift()];
3,656✔
510

511
    parts.forEach(prop => {
3,656✔
UNCOV
512
        if (current) {
×
UNCOV
513
            current = current[prop];
×
514
        }
515
    });
516

517
    return current;
3,656✔
518
};
519

520
/**
521
 *
522
 * Given a property access path in the format `x.y.z` and a value
523
 * this functions builds and returns an object following the access path.
524
 *
525
 * @example
526
 * ```typescript
527
 * console.log('x.y.z.', 42);
528
 * >> { x: { y: { z: 42 } } }
529
 * ```
530
 *
531
 * @hidden
532
 * @internal
533
 */
534
export const reverseMapper = (path: string, value: any) => {
2✔
UNCOV
535
    const obj = {};
×
UNCOV
536
    const parts = path?.split('.') ?? [];
×
537

UNCOV
538
    let _prop = parts.shift();
×
539
    let mapping: any;
540

541
    // Initial binding for first level bindings
UNCOV
542
    obj[_prop] = value;
×
UNCOV
543
    mapping = obj;
×
544

UNCOV
545
    parts.forEach(prop => {
×
546
        // Start building the hierarchy
UNCOV
547
        mapping[_prop] = {};
×
548
        // Go down a level
UNCOV
549
        mapping = mapping[_prop];
×
550
        // Bind the value and move the key
UNCOV
551
        mapping[prop] = value;
×
UNCOV
552
        _prop = prop;
×
553
    });
554

UNCOV
555
    return obj;
×
556
};
557

558
export const yieldingLoop = (count: number, chunkSize: number, callback: (index: number) => void, done: () => void) => {
2✔
UNCOV
559
    let i = 0;
×
UNCOV
560
    const chunk = () => {
×
UNCOV
561
        const end = Math.min(i + chunkSize, count);
×
UNCOV
562
        for (; i < end; ++i) {
×
UNCOV
563
            callback(i);
×
564
        }
UNCOV
565
        if (i < count) {
×
UNCOV
566
            setImmediate(chunk);
×
567
        } else {
UNCOV
568
            done();
×
569
        }
570
    };
UNCOV
571
    chunk();
×
572
};
573

574
export const isConstructor = (ref: any) => typeof ref === 'function' && Boolean(ref.prototype) && Boolean(ref.prototype.constructor);
258✔
575

576
/**
577
 * Similar to Angular's formatDate. However it will not throw on `undefined | null | ''` instead
578
 * coalescing to an empty string.
579
 */
580
export const formatDate = (value: string | number | Date, format: string, locale: string, timezone?: string): string => {
2✔
581
    if (value === null || value === undefined || value === '') {
2,643✔
582
        return '';
879✔
583
    }
584
    return _formatDate(value, format, locale, timezone);
1,764✔
585
};
586

587
export const formatCurrency = new CurrencyPipe(undefined).transform;
2✔
588

589
/** Converts pixel values to their rem counterparts for a base value */
590
export const rem = (value: number | string) => {
2✔
591
    const base = parseFloat(globalThis.window?.getComputedStyle(globalThis.document?.documentElement).getPropertyValue('--ig-base-font-size'))
726✔
592
    return Number(value) / base;
726✔
593
}
594

595
/** Get the size of the component as derived from the CSS size variable */
596
export function getComponentSize(el: Element) {
UNCOV
597
    return globalThis.window?.getComputedStyle(el).getPropertyValue('--component-size');
×
598
}
599

600
/** Get the first item in an array */
601
export function first<T>(arr: T[]) {
UNCOV
602
    return arr.at(0) as T;
×
603
}
604

605
/** Get the last item in an array */
606
export function last<T>(arr: T[]) {
UNCOV
607
    return arr.at(-1) as T;
×
608
}
609

610
/** Calculates the modulo of two numbers, ensuring a non-negative result. */
611
export function modulo(n: number, d: number) {
UNCOV
612
    return ((n % d) + d) % d;
×
613
}
614

615
/**
616
 * Splits an array into chunks of length `size` and returns a generator
617
 * yielding each chunk.
618
 * The last chunk may contain less than `size` elements.
619
 *
620
 * @example
621
 * ```typescript
622
 * const arr = [0,1,2,3,4,5,6,7,8,9];
623
 *
624
 * Array.from(chunk(arr, 2)) // [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]
625
 * Array.from(chunk(arr, 3)) // [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
626
 * Array.from(chunk([], 3)) // []
627
 * Array.from(chunk(arr, -3)) // Error
628
 * ```
629
 */
630
export function* intoChunks<T>(arr: T[], size: number) {
UNCOV
631
  if (size < 1) {
×
632
    throw new Error('size must be an integer >= 1');
×
633
  }
UNCOV
634
  for (let i = 0; i < arr.length; i += size) {
×
UNCOV
635
    yield arr.slice(i, i + size);
×
636
  }
637
}
638

639
/**
640
 * @param size
641
 * @returns string that represents the --component-size default value
642
 */
643
export function getComponentCssSizeVar(size: string) {
644
    switch (size) {
×
645
        case "1":
646
            return 'var(--ig-size, var(--ig-size-small))';
×
647
        case "2":
648
            return 'var(--ig-size, var(--ig-size-medium))';
×
649
        case "3":
650
        default:
651
            return 'var(--ig-size, var(--ig-size-large))';
×
652
    }
653
}
654

655
/**
656
 * @param path - The URI path to be normalized.
657
 * @returns string encoded using the encodeURI function.
658
 */
659
 export function normalizeURI(path: string) {
UNCOV
660
    return path?.split('/').map(encodeURI).join('/');
×
661
 }
662

663
export function getComponentTheme(el: Element) {
664
    return globalThis.window
2,753✔
665
    ?.getComputedStyle(el)
666
    .getPropertyValue('--theme')
667
    .trim() as IgxTheme;
668
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc