@nativerent/js-utils 1.0.0 → 1.0.1
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.
- package/README.md +3 -1
- package/dist/index.d.ts +139 -5
- package/dist/index.js +357 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +319 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +542 -5
- package/src/types.d.ts +7 -1
- package/tests/tests.ts +224 -0
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Primitive } from "./types";
|
|
1
|
+
import { FlattenableObject, Primitive, SimpleObject } from "./types";
|
|
2
2
|
|
|
3
3
|
export function debounce(fn: Function, delay: number): () => void {
|
|
4
4
|
let timeout: ReturnType<typeof setTimeout>;
|
|
@@ -118,22 +118,75 @@ export function getObjectKeys(object: object): string[] {
|
|
|
118
118
|
|
|
119
119
|
/**
|
|
120
120
|
* Works with primitive objects, see JSDoc @param
|
|
121
|
-
*
|
|
122
|
-
* @param object {[key: string]: SimpleObject | { [key: string]: SimpleObject }}
|
|
123
121
|
*/
|
|
124
|
-
export function objectToQueryString(object:
|
|
122
|
+
export function objectToQueryString(object: {
|
|
123
|
+
[key: string]: SimpleObject | { [key: string]: SimpleObject };
|
|
124
|
+
}): string {
|
|
125
125
|
return Object.entries(object)
|
|
126
126
|
.map(([k, v]) => {
|
|
127
127
|
if (Array.isArray(v)) {
|
|
128
128
|
return v.map((item) => `${k}[]=${encodeURIComponent(item)}`).join("&");
|
|
129
129
|
} else if (isObject(v)) {
|
|
130
|
-
|
|
130
|
+
return `${k}=${encodeURIComponent(JSON.stringify(v))}`;
|
|
131
131
|
}
|
|
132
132
|
return `${k}=${encodeURIComponent(v || "")}`;
|
|
133
133
|
})
|
|
134
134
|
.join("&");
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
export function countObjectInnerLength(object: {
|
|
138
|
+
[key: string | number]: any;
|
|
139
|
+
}) {
|
|
140
|
+
const obj = Object.values(object);
|
|
141
|
+
|
|
142
|
+
return obj.length === 1
|
|
143
|
+
? obj[0].length
|
|
144
|
+
: obj.reduce((acc, cur) => {
|
|
145
|
+
if (Array.isArray(acc)) {
|
|
146
|
+
acc = acc.length;
|
|
147
|
+
}
|
|
148
|
+
if (cur) {
|
|
149
|
+
acc += cur.length;
|
|
150
|
+
}
|
|
151
|
+
return acc;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Check if the element is in viewport
|
|
157
|
+
*/
|
|
158
|
+
export const isElementVisible = (
|
|
159
|
+
element: HTMLElement,
|
|
160
|
+
minVisiblePercent = 50,
|
|
161
|
+
) => {
|
|
162
|
+
const elementCoords = element.getBoundingClientRect();
|
|
163
|
+
const elementHeight = elementCoords.height;
|
|
164
|
+
|
|
165
|
+
if (!elementHeight) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const elementTop = elementCoords.top;
|
|
170
|
+
const elementBottom = elementCoords.bottom;
|
|
171
|
+
const viewPortHeight = window.innerHeight;
|
|
172
|
+
|
|
173
|
+
const elementVisibleHeight =
|
|
174
|
+
elementTop > 0
|
|
175
|
+
? // the element is in or below viewport
|
|
176
|
+
viewPortHeight - elementTop
|
|
177
|
+
: // the element is still in or above viewport
|
|
178
|
+
elementBottom;
|
|
179
|
+
|
|
180
|
+
return (elementVisibleHeight / elementHeight) * 100 >= minVisiblePercent;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Find a DOM element where an ad unit should be rendered to
|
|
185
|
+
*/
|
|
186
|
+
export function getHtmlElement(id: string) {
|
|
187
|
+
return document.getElementById(id);
|
|
188
|
+
}
|
|
189
|
+
|
|
137
190
|
export function decodeSafeURL(url: string): string {
|
|
138
191
|
try {
|
|
139
192
|
return decodeURI(url);
|
|
@@ -340,6 +393,18 @@ export function createStyleElement(css: string | null) {
|
|
|
340
393
|
return element;
|
|
341
394
|
}
|
|
342
395
|
|
|
396
|
+
/**
|
|
397
|
+
* Create a <link> element
|
|
398
|
+
*/
|
|
399
|
+
export function createLinkElement(href: string) {
|
|
400
|
+
const element = createHtmlElement("link") as HTMLLinkElement;
|
|
401
|
+
|
|
402
|
+
element.rel = "stylesheet";
|
|
403
|
+
element.href = href;
|
|
404
|
+
|
|
405
|
+
return element;
|
|
406
|
+
}
|
|
407
|
+
|
|
343
408
|
/**
|
|
344
409
|
* Create svg elements
|
|
345
410
|
*/
|
|
@@ -360,3 +425,475 @@ export function createSvgElement(
|
|
|
360
425
|
|
|
361
426
|
return element;
|
|
362
427
|
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Append a new script element to the DOM head
|
|
431
|
+
*/
|
|
432
|
+
export function insertJs(js: string, inline = false) {
|
|
433
|
+
const element = createScriptElement(js, inline);
|
|
434
|
+
|
|
435
|
+
document.head.appendChild(element);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Append a new style element to the DOM head
|
|
440
|
+
*/
|
|
441
|
+
export const insertCss = (
|
|
442
|
+
css: string,
|
|
443
|
+
className?: string,
|
|
444
|
+
external = false,
|
|
445
|
+
) => {
|
|
446
|
+
const element = external ? createLinkElement(css) : createStyleElement(css);
|
|
447
|
+
|
|
448
|
+
if (className) {
|
|
449
|
+
element.className = className;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
document.head.appendChild(element);
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Get screen sizes
|
|
457
|
+
*/
|
|
458
|
+
export function getScreenSize(): { width: number; height: number } {
|
|
459
|
+
let width, height;
|
|
460
|
+
|
|
461
|
+
if (window.screen) {
|
|
462
|
+
width = screen.width;
|
|
463
|
+
height = screen.height;
|
|
464
|
+
} else {
|
|
465
|
+
width = window.innerWidth;
|
|
466
|
+
height = window.innerHeight;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return {
|
|
470
|
+
width: width,
|
|
471
|
+
height: height,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Get a random integer between min and max
|
|
477
|
+
*/
|
|
478
|
+
export function getRandomInt(min = 0, max = 4294967295) {
|
|
479
|
+
min = Math.ceil(min);
|
|
480
|
+
max = Math.floor(max);
|
|
481
|
+
|
|
482
|
+
return Math.floor(Math.random() * (max - min)) + min;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Create an image element to use as a tracking pixel
|
|
487
|
+
*/
|
|
488
|
+
export function createPixelElement(src: string) {
|
|
489
|
+
const image = document.createElement("img");
|
|
490
|
+
|
|
491
|
+
image.src = src;
|
|
492
|
+
image.width = 1;
|
|
493
|
+
image.height = 1;
|
|
494
|
+
image.style.position = "absolute";
|
|
495
|
+
image.style.left = "-99999px";
|
|
496
|
+
|
|
497
|
+
return image;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Implementation of Java's String.hashCode() method
|
|
502
|
+
*/
|
|
503
|
+
export function hashCode(str: string) {
|
|
504
|
+
let hash = 0,
|
|
505
|
+
chr;
|
|
506
|
+
|
|
507
|
+
for (let i = 0; i < str.length; i++) {
|
|
508
|
+
chr = str.charCodeAt(i);
|
|
509
|
+
hash = (hash << 5) - hash + chr;
|
|
510
|
+
hash |= 0; // convert to 32bit integer
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return hash >>> 0;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Executes a callback as soon as DOM is interactive
|
|
518
|
+
*/
|
|
519
|
+
export function onDOMReady(callback: Function, ...args: any[]) {
|
|
520
|
+
if (
|
|
521
|
+
document.readyState === "interactive" ||
|
|
522
|
+
document.readyState === "complete"
|
|
523
|
+
) {
|
|
524
|
+
callback(...args);
|
|
525
|
+
} else {
|
|
526
|
+
document.addEventListener("DOMContentLoaded", () => callback(...args));
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Calculate the percentage of two values
|
|
532
|
+
*
|
|
533
|
+
* @param a
|
|
534
|
+
* @param b
|
|
535
|
+
* @return number
|
|
536
|
+
*/
|
|
537
|
+
export function toPercent(a: number, b: number): number {
|
|
538
|
+
return b > 0 ? (a / b) * 100 : 0;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Make a camelCase string
|
|
543
|
+
*
|
|
544
|
+
* @param string
|
|
545
|
+
* @return string
|
|
546
|
+
*/
|
|
547
|
+
export function toCamelCase(string: string): string {
|
|
548
|
+
return string
|
|
549
|
+
.split(new RegExp(/[-_.]/))
|
|
550
|
+
.reduce(
|
|
551
|
+
(a: string, b: string) => a + b.charAt(0).toUpperCase() + b.slice(1),
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Make a snake_case string
|
|
557
|
+
*
|
|
558
|
+
* @param string
|
|
559
|
+
* @return string
|
|
560
|
+
*/
|
|
561
|
+
export function toSnakeCase(string: string): string {
|
|
562
|
+
return toCamelCase(string)
|
|
563
|
+
.replace(/(^[A-Z])?([A-Z])/gm, "$1_$2")
|
|
564
|
+
.toLowerCase();
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Transform the first letter of the given string to the upper case
|
|
569
|
+
*
|
|
570
|
+
* @param string
|
|
571
|
+
* @return string
|
|
572
|
+
*/
|
|
573
|
+
export function capitalize(string: string): string {
|
|
574
|
+
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Registry independent string sorting
|
|
579
|
+
*
|
|
580
|
+
* @param first
|
|
581
|
+
* @param second
|
|
582
|
+
*/
|
|
583
|
+
export function sortByAlphabet(first: string, second: string): number {
|
|
584
|
+
return first.toLowerCase() > second.toLowerCase() ? 1 : -1;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* @param length
|
|
589
|
+
* @return string of max length 100
|
|
590
|
+
*/
|
|
591
|
+
export function getRandomStr(length?: number): string {
|
|
592
|
+
length = length ? (length > 100 ? 100 : length) : 10;
|
|
593
|
+
|
|
594
|
+
let str = Math.random().toString(36).substring(2);
|
|
595
|
+
|
|
596
|
+
while (str.length < length) {
|
|
597
|
+
str += Math.random().toString(36).substring(2);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const result = str.slice(-length);
|
|
601
|
+
return isNaN(Number(result)) ? result : getRandomStr(length);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
export function getRandomItem(items: any[]): any {
|
|
605
|
+
return items[Math.floor(Math.random() * items.length)];
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Summarize elements of the given array
|
|
610
|
+
*
|
|
611
|
+
* @param values
|
|
612
|
+
* @return number | string - a summary of all the numbers in the array or an empty string if
|
|
613
|
+
* there was only NaNs
|
|
614
|
+
*/
|
|
615
|
+
export function sumArray(values: Array<any>): number | string {
|
|
616
|
+
if (values.every((value: any) => isNaN(value))) {
|
|
617
|
+
return "";
|
|
618
|
+
} else {
|
|
619
|
+
return values.reduce((sum: any, curr: any) => {
|
|
620
|
+
const value = Number(curr);
|
|
621
|
+
|
|
622
|
+
if (!isNaN(value)) {
|
|
623
|
+
return sum + value;
|
|
624
|
+
} else {
|
|
625
|
+
return sum;
|
|
626
|
+
}
|
|
627
|
+
}, 0);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Returns an array of the object keys which values are not present in filter
|
|
633
|
+
*
|
|
634
|
+
* @param obj
|
|
635
|
+
* @param values
|
|
636
|
+
*/
|
|
637
|
+
export function filterObjectKeysByValues(
|
|
638
|
+
obj: { [key: string]: any },
|
|
639
|
+
values: Array<string | number | boolean | null | undefined>,
|
|
640
|
+
): string[] {
|
|
641
|
+
values = Array.isArray(values) ? values : Array(values);
|
|
642
|
+
|
|
643
|
+
const keys = [];
|
|
644
|
+
|
|
645
|
+
for (const key in obj) {
|
|
646
|
+
if (!values.includes(obj[key])) {
|
|
647
|
+
keys.push(key);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return keys;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
export function getFromObject(object: object, key: string): any {
|
|
655
|
+
return key.split(".").reduce((a: any, b: any) => {
|
|
656
|
+
return a[b];
|
|
657
|
+
}, object);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
export function fireBlurEvent(
|
|
661
|
+
element: string | Element | null,
|
|
662
|
+
delay: number = 0,
|
|
663
|
+
): void {
|
|
664
|
+
fireEvent("blur", element, delay);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
export function fireInputEvent(
|
|
668
|
+
element: string | Element | null,
|
|
669
|
+
delay: number = 0,
|
|
670
|
+
): void {
|
|
671
|
+
fireEvent("input", element, delay);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
export function fireEvent(
|
|
675
|
+
eventName: string,
|
|
676
|
+
element: string | Element | null,
|
|
677
|
+
delay: number = 0,
|
|
678
|
+
): void {
|
|
679
|
+
setTimeout(() => {
|
|
680
|
+
if (isString(element)) {
|
|
681
|
+
element = document.querySelector(element);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
if (!isNullOrUndef(element)) {
|
|
685
|
+
element.dispatchEvent(
|
|
686
|
+
new Event(eventName, {
|
|
687
|
+
bubbles: true,
|
|
688
|
+
}),
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
}, delay);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export function hasObjectChanged(
|
|
695
|
+
object: { [key: string]: any },
|
|
696
|
+
values: any[],
|
|
697
|
+
): boolean {
|
|
698
|
+
let hasChanged = false;
|
|
699
|
+
|
|
700
|
+
for (const key in object) {
|
|
701
|
+
let oldVal = object[key];
|
|
702
|
+
let [, newVal] = values.find(([newKey]) => key === newKey);
|
|
703
|
+
|
|
704
|
+
if (isObject(oldVal)) {
|
|
705
|
+
if (!isObject(newVal)) {
|
|
706
|
+
hasChanged = true;
|
|
707
|
+
} else {
|
|
708
|
+
hasChanged = hasObjectChanged(oldVal, Object.entries(newVal));
|
|
709
|
+
}
|
|
710
|
+
} else if (Array.isArray(newVal) || Array.isArray(oldVal)) {
|
|
711
|
+
newVal = Array.isArray(newVal) ? newVal : [];
|
|
712
|
+
oldVal = Array.isArray(oldVal) ? oldVal : [];
|
|
713
|
+
|
|
714
|
+
hasChanged = arrayDiff(newVal, oldVal).length > 0;
|
|
715
|
+
} else {
|
|
716
|
+
hasChanged = areDiff(newVal, oldVal);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (hasChanged) {
|
|
720
|
+
break;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return hasChanged;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
export function roundBigNum(number: number): number {
|
|
728
|
+
const digitsNum = Math.trunc(number).toString().length;
|
|
729
|
+
|
|
730
|
+
let roundTo = 0;
|
|
731
|
+
switch (true) {
|
|
732
|
+
case digitsNum > 2 && digitsNum < 5:
|
|
733
|
+
roundTo = 100;
|
|
734
|
+
break;
|
|
735
|
+
case digitsNum >= 5:
|
|
736
|
+
roundTo = 10000;
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
return roundTo ? Math.round(number / roundTo) * roundTo : number;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
export function extractNumbers(value: any): string {
|
|
744
|
+
if (!isStr(value) && !isNum(value)) {
|
|
745
|
+
return "";
|
|
746
|
+
}
|
|
747
|
+
return value.toString().replace(/[^0-9]/g, "");
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
export function removeSpaces(value: any): string {
|
|
751
|
+
if (!isStr(value) && !isNum(value)) {
|
|
752
|
+
return "";
|
|
753
|
+
}
|
|
754
|
+
return value.toString().replace(/\s/g, "");
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
export function roundUp(num: number, precision: number): number {
|
|
758
|
+
const multiplier = Number("1".padEnd(precision + 1, "0"));
|
|
759
|
+
return Math.ceil(num * multiplier) / multiplier;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
export function roundDown(num: number, precision: number): number {
|
|
763
|
+
const multiplier = Number("1".padEnd(precision + 1, "0"));
|
|
764
|
+
return Math.floor(num * multiplier) / multiplier;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
export function areDiff(
|
|
768
|
+
val1?: Primitive | null,
|
|
769
|
+
val2?: Primitive | null,
|
|
770
|
+
strict?: boolean,
|
|
771
|
+
): boolean {
|
|
772
|
+
if (strict) {
|
|
773
|
+
return val1 !== val2;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// at least one value is not empty
|
|
777
|
+
if (Boolean(val1) || Boolean(val2)) {
|
|
778
|
+
return val1 != val2;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// both empty, but not equally empty!
|
|
782
|
+
// each one may be one of: empty string, null or undefined
|
|
783
|
+
return false;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
export function flattenObject(obj: FlattenableObject, prefix = "") {
|
|
787
|
+
return Object.keys(obj).reduce((acc, k) => {
|
|
788
|
+
const pre = prefix.length ? prefix + "." : "";
|
|
789
|
+
if (isObject(obj[k]) || Array.isArray(obj[k])) {
|
|
790
|
+
Object.assign(acc, flattenObject(obj[k], pre + k));
|
|
791
|
+
} else {
|
|
792
|
+
acc[pre + k] = obj[k];
|
|
793
|
+
}
|
|
794
|
+
return acc;
|
|
795
|
+
}, {} as FlattenableObject);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
export function flattenObjectAsArray(obj: FlattenableObject) {
|
|
799
|
+
const result: FlattenableObject = {};
|
|
800
|
+
const flat = flattenObject(obj);
|
|
801
|
+
Object.keys(flat).forEach((key) => {
|
|
802
|
+
const newKey = key.replaceAll(/\.([^.]+)/g, "[$1]");
|
|
803
|
+
result[newKey] = flat[key];
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
return result;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
export function parseObjectPathStr(pathStr: string): string[] {
|
|
810
|
+
const pathParts = pathStr.replace(/\[/g, ".").replace(/\]/g, "").split(".");
|
|
811
|
+
|
|
812
|
+
if (pathParts.length > 1 && pathParts[1].includes("[")) {
|
|
813
|
+
return [pathParts[0], ...parseObjectPathStr(pathParts[1])];
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
return pathParts;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
export function formatNumber(
|
|
820
|
+
num: number | string,
|
|
821
|
+
fractionDigits?: number,
|
|
822
|
+
): string {
|
|
823
|
+
fractionDigits = isNullOrUndef(fractionDigits) ? 2 : fractionDigits;
|
|
824
|
+
return new Intl.NumberFormat("ru-RU", {
|
|
825
|
+
style: "decimal",
|
|
826
|
+
minimumFractionDigits: fractionDigits,
|
|
827
|
+
maximumFractionDigits: fractionDigits,
|
|
828
|
+
})
|
|
829
|
+
.format(Number(num))
|
|
830
|
+
.replace(",", ".")
|
|
831
|
+
.replace(/\u00A0/g, " "); // charCode 160, White-space
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
export function formatNumberWithSign(
|
|
835
|
+
num: number | string,
|
|
836
|
+
fractionDigits?: number,
|
|
837
|
+
): string {
|
|
838
|
+
return formatWithSign(num, formatNumber(num, fractionDigits));
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
export function formatPercent(num: number | string): string {
|
|
842
|
+
return formatNumber(num) + "%";
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
export function formatWithSign(
|
|
846
|
+
num: number | string,
|
|
847
|
+
numString?: string,
|
|
848
|
+
): string {
|
|
849
|
+
numString = numString ? numString : num.toString();
|
|
850
|
+
return (Number(num) < 0 ? "" : "+") + numString;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
export function autoSizeText(
|
|
854
|
+
el: HTMLElement,
|
|
855
|
+
height: number,
|
|
856
|
+
minFontSize: number,
|
|
857
|
+
maxFontSize: number = 50,
|
|
858
|
+
) {
|
|
859
|
+
let attempts = 30;
|
|
860
|
+
|
|
861
|
+
const resizeText = () => {
|
|
862
|
+
if (getTextHeight() === 0) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
while (attempts && getTextHeight() > height) {
|
|
866
|
+
attempts--;
|
|
867
|
+
reduceText();
|
|
868
|
+
}
|
|
869
|
+
while (attempts && getTextHeight() < height) {
|
|
870
|
+
attempts--;
|
|
871
|
+
enlargeText();
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
const reduceText = () => {
|
|
876
|
+
const fontSize = getNumericStyleProp("fontSize", el);
|
|
877
|
+
const newFontSize = fontSize - 1;
|
|
878
|
+
if (fontSize > 1 && newFontSize >= minFontSize) {
|
|
879
|
+
el.style.fontSize = `${newFontSize}px`;
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
const enlargeText = () => {
|
|
884
|
+
const fontSize = getNumericStyleProp("fontSize", el);
|
|
885
|
+
const newFontSize = fontSize + 1;
|
|
886
|
+
if (newFontSize <= maxFontSize) {
|
|
887
|
+
el.style.fontSize = `${newFontSize}px`;
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
const getTextHeight = () =>
|
|
892
|
+
Math.floor(
|
|
893
|
+
el.scrollHeight -
|
|
894
|
+
getNumericStyleProp("paddingTop", el) -
|
|
895
|
+
getNumericStyleProp("paddingBottom", el),
|
|
896
|
+
);
|
|
897
|
+
|
|
898
|
+
resizeText();
|
|
899
|
+
}
|
package/src/types.d.ts
CHANGED