@rabex-kit/rabex-ui 0.2.45 → 0.2.47

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.
@@ -381,73 +381,214 @@ function useOnScreen(ref, options) {
381
381
  return isIntersecting;
382
382
  }
383
383
 
384
+ // ============================================================================
385
+ // CONSTANTS & TYPE DEFINITIONS
386
+ // ============================================================================
387
+ /**
388
+ * Persian/Farsi numerals mapping to English numerals
389
+ * Used for localization and number format conversion
390
+ */
384
391
  var persianNumber = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
392
+ /**
393
+ * Standard English numerals
394
+ * Target format for all numeric operations
395
+ */
385
396
  var englishNumber = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
397
+ /**
398
+ * Valid decimal and thousand separator characters
399
+ * Allows both period and comma based on locale preferences
400
+ */
386
401
  var charachter = ['.', ','];
402
+ // ============================================================================
403
+ // CORE UTILITY FUNCTIONS - SCIENTIFIC NOTATION SAFE
404
+ // ============================================================================
405
+ /**
406
+ * Detect the number of meaningful decimal places in a number
407
+ * @param num - The number to analyze
408
+ * @returns Number of decimal places that contain meaningful data
409
+ */
410
+ var detectPrecision = function detectPrecision(num) {
411
+ if (num === 0) return 0;
412
+ // Convert to string to analyze the original input precision
413
+ var str = num.toString();
414
+ // Handle scientific notation
415
+ if (str.includes('e')) {
416
+ var _str$split = str.split('e'),
417
+ base = _str$split[0],
418
+ exp = _str$split[1];
419
+ var exponent = parseInt(exp);
420
+ var baseDecimals = base.includes('.') ? base.split('.')[1].length : 0;
421
+ if (exponent < 0) {
422
+ return Math.abs(exponent) + baseDecimals;
423
+ } else {
424
+ return Math.max(0, baseDecimals - exponent);
425
+ }
426
+ }
427
+ // Handle regular decimal notation
428
+ if (str.includes('.')) {
429
+ return str.split('.')[1].length;
430
+ }
431
+ return 0;
432
+ };
433
+ /**
434
+ * CONVERT SCIENTIFIC NOTATION TO DECIMAL STRING
435
+ *
436
+ * Purpose: Prevents scientific notation (1e-8) by converting to decimal format (0.00000001)
437
+ *
438
+ * @param num - Input number in any format (number, string, scientific notation)
439
+ * @returns Decimal string representation or undefined if invalid
440
+ *
441
+ * Key Features:
442
+ * - Handles very large numbers using BigInt
443
+ * - Handles very small numbers with proper decimal places
444
+ * - Returns undefined for invalid inputs (NaN, null, undefined)
445
+ * - Uses toFixed(20) to ensure adequate precision
446
+ * - Removes trailing zeros for clean output
447
+ *
448
+ * Examples:
449
+ * convertScientific(1e-8) → "0.00000001"
450
+ * convertScientific(1e8) → "100000000"
451
+ * convertScientific("abc") → undefined
452
+ */
453
+ var convertScientific = function convertScientific(num) {
454
+ if (num === null || num === undefined || num === '') {
455
+ return undefined;
456
+ }
457
+ var numValue = Number(num);
458
+ if (isNaN(numValue) || !isFinite(numValue)) {
459
+ return undefined;
460
+ }
461
+ if (numValue === 0) return '0';
462
+ // Handle very large integers
463
+ if (Math.abs(numValue) >= 1e15 && Number.isInteger(numValue)) {
464
+ return BigInt(Math.round(numValue)).toString();
465
+ }
466
+ // Handle very small numbers
467
+ if (Math.abs(numValue) < 1e-15) {
468
+ return '0';
469
+ }
470
+ // SOLUTION 1: Intelligent precision detection
471
+ var detectedPrecision = detectPrecision(numValue);
472
+ var safePrecision = Math.min(detectedPrecision + 2, 15); // Add buffer but cap at 15
473
+ var result = numValue.toFixed(safePrecision).replace(/\.?0+$/, '');
474
+ return result;
475
+ };
476
+ /**
477
+ * SAFE NUMBER CONVERSION
478
+ *
479
+ * Purpose: Wrapper around convertScientific that always returns a valid string
480
+ *
481
+ * @param num - Input number in any format
482
+ * @returns Decimal string representation (defaults to '0' if conversion fails)
483
+ *
484
+ * This is the primary function used throughout the library to ensure
485
+ * all number inputs are converted to safe decimal strings before processing
486
+ */
487
+ var safeNumber = function safeNumber(num) {
488
+ return convertScientific(num) || '0';
489
+ };
490
+ // ============================================================================
491
+ // FORMATTING & DISPLAY FUNCTIONS
492
+ // ============================================================================
493
+ /**
494
+ * NUMBER SUFFIX FORMATTER (K, M, B, T)
495
+ *
496
+ * Purpose: Converts large numbers to human-readable format with suffixes
497
+ *
498
+ * @param num - Input number to format
499
+ * @param options - Formatting options (precision, rounding method, allowed suffixes)
500
+ * @returns Formatted string with appropriate suffix
501
+ *
502
+ * Key Features:
503
+ * - Uses bigDecimal for all calculations to avoid scientific notation
504
+ * - Supports custom precision and rounding methods
505
+ * - Configurable suffix types (K=thousands, M=millions, B=billions, T=trillions)
506
+ * - Falls back to original number if no suffix applies
507
+ *
508
+ * Examples:
509
+ * suffix(1000, {precision: 1}) → "1K"
510
+ * suffix(1500000, {precision: 2, round: 'roundUp'}) → "1.5M"
511
+ * suffix(2.5e9) → "2.5B"
512
+ *
513
+ * Scientific Notation Prevention:
514
+ * - Uses string-based thresholds instead of numeric literals
515
+ * - BigDecimal comparison instead of JavaScript's Math.abs()
516
+ * - BigDecimal division instead of standard division operator
517
+ */
387
518
  function suffix(num, options) {
388
- var _ref = options || {},
389
- _ref$precision = _ref.precision,
390
- precision = _ref$precision === void 0 ? 3 : _ref$precision,
391
- _ref$round = _ref.round,
392
- round = _ref$round === void 0 ? 'roundDown' : _ref$round,
393
- _ref$suffix = _ref.suffix,
394
- suffix = _ref$suffix === void 0 ? ['B', 'T'] : _ref$suffix;
519
+ if (options === void 0) {
520
+ options = {};
521
+ }
522
+ var _options = options,
523
+ _options$precision = _options.precision,
524
+ precision = _options$precision === void 0 ? 3 : _options$precision,
525
+ _options$round = _options.round,
526
+ round = _options$round === void 0 ? 'roundDown' : _options$round,
527
+ _options$suffix = _options.suffix,
528
+ suffix = _options$suffix === void 0 ? ['B', 'T'] : _options$suffix;
529
+ // Define thresholds as strings to avoid floating point precision issues
395
530
  var map = [{
396
531
  suffix: 'T',
397
- threshold: 1e12
532
+ threshold: '1000000000000'
398
533
  }, {
399
534
  suffix: 'B',
400
- threshold: 1e9
535
+ threshold: '1000000000'
401
536
  }, {
402
537
  suffix: 'M',
403
- threshold: 1e6
538
+ threshold: '1000000'
404
539
  }, {
405
540
  suffix: 'K',
406
- threshold: 1e3
541
+ threshold: '1000'
407
542
  }, {
408
543
  suffix: '$',
409
- threshold: 1
544
+ threshold: '1'
410
545
  }];
546
+ // Convert input to safe decimal string
547
+ var numStr = safeNumber(num);
548
+ // Find appropriate suffix using bigDecimal comparison
411
549
  var found = map.find(function (x) {
412
- return Math.abs(Number(num)) >= x.threshold && _includes([].concat(suffix, ['$']), x.suffix);
550
+ var comparison = bigDecimal.compareTo(bigDecimal.abs(numStr), x.threshold);
551
+ return comparison >= 0 && _includes([].concat(suffix, ['$']), x.suffix);
413
552
  });
553
+ // Reference to enhanced rounding functions
414
554
  var func = {
415
- roundDown: _roundDown,
416
- roundUp: _roundUp
555
+ roundDown: enhancedRoundDown,
556
+ roundUp: enhancedRoundUp
417
557
  };
418
558
  if (found) {
419
- var formatted = func[round](Number(num) / found.threshold, precision) + (found.suffix === '$' ? '' : found.suffix);
559
+ // Use bigDecimal division to maintain precision
560
+ var divided = bigDecimal.divide(numStr, found.threshold, precision + 2);
561
+ var formatted = func[round](parseFloat(divided), precision) + (found.suffix === '$' ? '' : found.suffix);
420
562
  return formatted;
421
563
  }
422
- return num.toString();
564
+ // Return original number if no suffix applies
565
+ return numStr;
423
566
  }
424
- var divide = function divide(num1, num2, precision) {
425
- if (Number(num1) === 0) console.log('can not divide by zero! - (arguments[0])');
426
- if (Number(num2) === 0) console.log('can not divide by zero! - (arguments[1])');
427
- var number1 = Number(num1) || 1;
428
- var number2 = Number(num2) || 1;
429
- return bigDecimal.divide(number1, number2, precision);
430
- };
431
- var _toEn = function toEn(num) {
432
- var find = [].concat(persianNumber, ['٫']);
433
- var replace = [].concat(englishNumber, ['.']);
434
- var replaceString = num;
435
- var regex;
436
- for (var i = 0; i < find.length; i++) {
437
- regex = new RegExp(find[i], 'g');
438
- replaceString = replaceString.replace(regex, replace[i]);
439
- }
440
- return replaceString;
441
- };
442
- var _isValid = function isValid(num) {
443
- var numbers = typeof num === 'number' ? num.toString() : num;
444
- if (numbers.length === 0) return true;
445
- var allowCharachter = [].concat(persianNumber, englishNumber, charachter);
446
- if (_includes(allowCharachter, numbers.slice(-1))) {
447
- return true;
448
- }
449
- return false;
450
- };
567
+ /**
568
+ * THOUSAND SEPARATOR FORMATTER
569
+ *
570
+ * Purpose: Adds thousand separators to numbers for improved readability
571
+ *
572
+ * @param num - Input number to format
573
+ * @param separator - Character to use as separator (default: comma)
574
+ * @param separateBy - Number of digits between separators (default: 3)
575
+ * @returns Formatted string with separators
576
+ *
577
+ * Key Features:
578
+ * - Preserves decimal places
579
+ * - Configurable separator character and grouping
580
+ * - Handles both number and string inputs
581
+ * - Uses safeNumber conversion to avoid scientific notation
582
+ *
583
+ * Examples:
584
+ * delimiter(1000) → "1,000"
585
+ * delimiter(1234567.89) → "1,234,567.89"
586
+ * delimiter(1000, '.', 3) "1.000"
587
+ *
588
+ * Scientific Notation Prevention:
589
+ * - Uses safeNumber() instead of toString() for number inputs
590
+ * - Ensures consistent decimal format before processing
591
+ */
451
592
  var _delimiter = function delimiter(num, separator, separateBy) {
452
593
  if (separator === void 0) {
453
594
  separator = ',';
@@ -455,75 +596,582 @@ var _delimiter = function delimiter(num, separator, separateBy) {
455
596
  if (separateBy === void 0) {
456
597
  separateBy = 3;
457
598
  }
458
- var numbers = typeof num === 'number' ? num.toString() : num;
599
+ // Convert number inputs to safe decimal string, keep strings as-is
600
+ var numbers = typeof num === 'number' ? safeNumber(num) : num;
459
601
  if (numbers) {
602
+ // Split into integer and decimal parts
460
603
  var parts = numbers.split('.');
604
+ // Create regex pattern for inserting separators
461
605
  var regex = new RegExp("(\\d)(?=(\\d{" + separateBy + "})+(?!\\d))", 'g');
606
+ // Apply separators to integer part, removing any existing separators first
462
607
  parts[0] = _replace(parts[0].split(',').join(''), regex, "$1" + separator);
608
+ // Rejoin integer and decimal parts
463
609
  return parts.join('.');
464
610
  }
465
611
  return num;
466
612
  };
613
+ /**
614
+ * REMOVE THOUSAND SEPARATORS
615
+ *
616
+ * Purpose: Removes thousand separators and returns clean decimal string
617
+ *
618
+ * @param num - Input string with separators
619
+ * @param separator - Separator character to remove (default: comma)
620
+ * @returns Clean decimal string without separators
621
+ *
622
+ * Key Features:
623
+ * - Returns string instead of number to prevent scientific notation
624
+ * - Uses safeNumber conversion for validation
625
+ * - Preserves original precision
626
+ *
627
+ * Examples:
628
+ * removeDelimiter("1,234,567") → "1234567"
629
+ * removeDelimiter("1.234.567", ".") → "1234567"
630
+ *
631
+ * Scientific Notation Prevention:
632
+ * - Returns string type instead of number
633
+ * - Uses safeNumber() for final validation
634
+ */
467
635
  var _removeDelimiter = function removeDelimiter(num, separator) {
468
636
  if (separator === void 0) {
469
637
  separator = ',';
470
638
  }
639
+ // Remove all instances of the separator character
471
640
  var cleanedNumber = num.split(separator).join('');
472
- return parseFloat(cleanedNumber);
641
+ // Return as safe decimal string instead of number to avoid scientific notation
642
+ return safeNumber(cleanedNumber);
473
643
  };
644
+ // ============================================================================
645
+ // MATHEMATICAL OPERATIONS - HIGH PRECISION
646
+ // ============================================================================
647
+ /**
648
+ * SAFE DIVISION WITH PRECISION
649
+ *
650
+ * Purpose: Performs division using bigDecimal to maintain precision
651
+ *
652
+ * @param num1 - Dividend (number being divided)
653
+ * @param num2 - Divisor (number dividing by)
654
+ * @param precision - Number of decimal places in result
655
+ * @returns Division result as decimal string
656
+ *
657
+ * Key Features:
658
+ * - Zero division protection with console warnings
659
+ * - Direct bigDecimal operations (no Number conversion)
660
+ * - Configurable precision
661
+ * - Returns '0' for invalid operations
662
+ *
663
+ * Examples:
664
+ * divide("10", "3", 4) → "3.3333"
665
+ * divide(1e-8, 2, 10) → "0.000000005"
666
+ *
667
+ * Scientific Notation Prevention:
668
+ * - Uses safeNumber() conversion before bigDecimal operations
669
+ * - No intermediate Number() conversions
670
+ * - BigDecimal maintains precision throughout calculation
671
+ */
672
+ var _divide = function divide(num1, num2, precision) {
673
+ if (precision === void 0) {
674
+ precision = 10;
675
+ }
676
+ // Convert inputs to safe decimal strings
677
+ var safeNum1 = safeNumber(num1);
678
+ var safeNum2 = safeNumber(num2);
679
+ // Check for division by zero in first operand
680
+ if (safeNum1 === '0') {
681
+ console.log('can not divide by zero! - (arguments[0])');
682
+ return '0';
683
+ }
684
+ // Check for division by zero in second operand
685
+ if (safeNum2 === '0') {
686
+ console.log('can not divide by zero! - (arguments[1])');
687
+ return '0';
688
+ }
689
+ // Perform division using bigDecimal for precision
690
+ return bigDecimal.divide(safeNum1, safeNum2, precision);
691
+ };
692
+ // ============================================================================
693
+ // ROUNDING FUNCTIONS - SCIENTIFIC NOTATION SAFE
694
+ // ============================================================================
695
+ /**
696
+ * ENHANCED ROUND UP FUNCTION
697
+ *
698
+ * Purpose: Rounds number up to specified decimal places using bigDecimal
699
+ *
700
+ * @param val - Number to round up
701
+ * @param dec - Number of decimal places
702
+ * @returns Rounded up value as formatted string
703
+ *
704
+ * Key Features:
705
+ * - Uses bigDecimal for all intermediate calculations
706
+ * - Handles zero decimal places (integer rounding)
707
+ * - Creates multipliers as strings to avoid precision loss
708
+ * - Formats output to remove unnecessary trailing zeros
709
+ *
710
+ * Algorithm:
711
+ * 1. Convert input to safe decimal string
712
+ * 2. For integer rounding, use bigDecimal.ceil directly
713
+ * 3. For decimal rounding, multiply by 10^dec, ceil, then divide back
714
+ * 4. Format result with proper decimal places
715
+ *
716
+ * Examples:
717
+ * enhancedRoundUp(3.14159, 2) → "3.15"
718
+ * enhancedRoundUp(1.1, 0) → "2"
719
+ * enhancedRoundUp(1e-8, 8) → "0.00000001"
720
+ *
721
+ * Scientific Notation Prevention:
722
+ * - No Number() conversions in calculations
723
+ * - String-based multiplier creation
724
+ * - BigDecimal operations maintain precision
725
+ */
726
+ var enhancedRoundUp = function enhancedRoundUp(val, dec) {
727
+ // Convert input to safe decimal string
728
+ var valStr = safeNumber(val);
729
+ // Handle integer rounding (no decimal places)
730
+ if (dec === 0) {
731
+ return bigDecimal.ceil(valStr).toString();
732
+ }
733
+ // Create multiplier as string: "1000" for dec=3, "100" for dec=2, etc.
734
+ var multiplier = '1' + '0'.repeat(dec);
735
+ // Multiply by power of 10 to shift decimal places
736
+ var multiplied = bigDecimal.multiply(valStr, multiplier);
737
+ // Apply ceiling function to get round-up behavior
738
+ var ceiled = bigDecimal.ceil(multiplied);
739
+ // Divide back to restore original decimal places
740
+ var result = bigDecimal.divide(ceiled, multiplier, dec);
741
+ // Format with fixed decimal places and remove trailing zeros
742
+ var formatted = parseFloat(result).toFixed(dec);
743
+ return formatted.replace(/^([\d,]+)$|^([\d,]+)\.0*$|^([\d,]+\.[0-9]*?)0*$/, '$1$2$3');
744
+ };
745
+ /**
746
+ * ENHANCED ROUND DOWN FUNCTION
747
+ *
748
+ * Purpose: Rounds number down to specified decimal places using bigDecimal
749
+ *
750
+ * @param val - Number to round down
751
+ * @param dec - Number of decimal places
752
+ * @returns Rounded down value as formatted string
753
+ *
754
+ * Key Features:
755
+ * - Identical to enhancedRoundUp but uses floor instead of ceil
756
+ * - Same precision-safe algorithm and string-based operations
757
+ *
758
+ * Algorithm:
759
+ * 1. Convert input to safe decimal string
760
+ * 2. For integer rounding, use bigDecimal.floor directly
761
+ * 3. For decimal rounding, multiply by 10^dec, floor, then divide back
762
+ * 4. Format result with proper decimal places
763
+ *
764
+ * Examples:
765
+ * enhancedRoundDown(3.14159, 2) → "3.14"
766
+ * enhancedRoundDown(1.9, 0) → "1"
767
+ * enhancedRoundDown(1e-8, 8) → "0.00000001"
768
+ */
769
+ var enhancedRoundDown = function enhancedRoundDown(val, dec) {
770
+ // Convert input to safe decimal string
771
+ var valStr = safeNumber(val);
772
+ // Handle integer rounding (no decimal places)
773
+ if (dec === 0) {
774
+ return bigDecimal.floor(valStr).toString();
775
+ }
776
+ // Create multiplier as string: "1000" for dec=3, "100" for dec=2, etc.
777
+ var multiplier = '1' + '0'.repeat(dec);
778
+ // Multiply by power of 10 to shift decimal places
779
+ var multiplied = bigDecimal.multiply(valStr, multiplier);
780
+ // Apply floor function to get round-down behavior
781
+ var floored = bigDecimal.floor(multiplied);
782
+ // Divide back to restore original decimal places
783
+ var result = bigDecimal.divide(floored, multiplier, dec);
784
+ // Format with fixed decimal places and remove trailing zeros
785
+ var formatted = parseFloat(result).toFixed(dec);
786
+ return formatted.replace(/^([\d,]+)$|^([\d,]+)\.0*$|^([\d,]+\.[0-9]*?)0*$/, '$1$2$3');
787
+ };
788
+ /**
789
+ * BACKWARD COMPATIBLE ROUND UP
790
+ *
791
+ * Purpose: Wrapper function maintaining original API while using enhanced implementation
792
+ */
474
793
  var _roundUp = function roundUp(val, dec) {
475
- var decimal = dec === 0 ? 0 : +("1" + new Array(dec + 1).join('0'));
476
- var result = decimal === 0 ? Math.ceil(val) : Math.ceil(+bigDecimal.multiply(val, decimal)) / decimal;
477
- return result ? result.toFixed(dec).replace(/^([\d,]+)$|^([\d,]+)\.0*$|^([\d,]+\.[0-9]*?)0*$/, '$1$2$3') : '0';
794
+ return enhancedRoundUp(val, dec);
478
795
  };
796
+ /**
797
+ * BACKWARD COMPATIBLE ROUND DOWN
798
+ *
799
+ * Purpose: Wrapper function maintaining original API while using enhanced implementation
800
+ */
479
801
  var _roundDown = function roundDown(val, dec) {
480
- var decimal = dec === 0 ? 0 : +("1" + new Array(dec + 1).join('0'));
481
- var result = decimal === 0 ? Math.floor(val) : Math.floor(+bigDecimal.multiply(val, decimal)) / decimal;
482
- return result ? result.toFixed(dec).replace(/^([\d,]+)$|^([\d,]+)\.0*$|^([\d,]+\.[0-9]*?)0*$/, '$1$2$3') : '0';
802
+ return enhancedRoundDown(val, dec);
483
803
  };
804
+ // ============================================================================
805
+ // VALIDATION & CONVERSION FUNCTIONS
806
+ // ============================================================================
807
+ /**
808
+ * PERSIAN TO ENGLISH NUMERAL CONVERTER
809
+ *
810
+ * Purpose: Converts Persian/Farsi numerals to English numerals
811
+ *
812
+ * @param num - Input string containing Persian numerals
813
+ * @returns String with English numerals
814
+ *
815
+ * Key Features:
816
+ * - Handles all Persian numeral characters (۰-۹)
817
+ * - Converts Persian decimal separator (٫) to period (.)
818
+ * - Uses regex replacement for efficient conversion
819
+ * - Pure string manipulation, no scientific notation risk
820
+ *
821
+ * Examples:
822
+ * toEn("۱۲۳۴") → "1234"
823
+ * toEn("۱۲٫۳۴") → "12.34"
824
+ *
825
+ * Algorithm:
826
+ * 1. Create mapping arrays for Persian to English characters
827
+ * 2. Iterate through each character mapping
828
+ * 3. Use regex to replace all instances globally
829
+ * 4. Return converted string
830
+ */
831
+ var _toEn = function toEn(num) {
832
+ // Characters to find (Persian numerals + Persian decimal separator)
833
+ var find = [].concat(persianNumber, ['٫']);
834
+ // Replacement characters (English numerals + period)
835
+ var replace = [].concat(englishNumber, ['.']);
836
+ var replaceString = num;
837
+ var regex;
838
+ // Replace each Persian character with its English equivalent
839
+ for (var i = 0; i < find.length; i++) {
840
+ regex = new RegExp(find[i], 'g'); // Global replacement
841
+ replaceString = replaceString.replace(regex, replace[i]);
842
+ }
843
+ return replaceString;
844
+ };
845
+ /**
846
+ * INPUT CHARACTER VALIDATOR
847
+ *
848
+ * Purpose: Validates if input contains only allowed numeric characters
849
+ *
850
+ * @param num - Input to validate (number or string)
851
+ * @returns Boolean indicating if input is valid
852
+ *
853
+ * Key Features:
854
+ * - Allows Persian numerals, English numerals, periods, and commas
855
+ * - Handles both number and string inputs
856
+ * - Checks only the last character for incremental validation
857
+ * - Returns true for empty strings (allows clearing input)
858
+ *
859
+ * Use Cases:
860
+ * - Real-time input validation in forms
861
+ * - Preventing invalid character entry
862
+ * - Supporting multiple numeral systems
863
+ *
864
+ * Examples:
865
+ * isValid("123") → true
866
+ * isValid("۱۲۳") → true
867
+ * isValid("12.34") → true
868
+ * isValid("12abc") → false
869
+ */
870
+ var _isValid = function isValid(num) {
871
+ // Convert number to string if needed
872
+ var numbers = typeof num === 'number' ? num.toString() : num;
873
+ // Allow empty input (user clearing the field)
874
+ if (numbers.length === 0) return true;
875
+ // Define all allowed characters
876
+ var allowCharachter = [].concat(persianNumber, englishNumber, charachter);
877
+ // Check if the last character is allowed (for incremental validation)
878
+ if (_includes(allowCharachter, numbers.slice(-1))) {
879
+ return true;
880
+ }
881
+ return false;
882
+ };
883
+ /**
884
+ * DECIMAL PLACES VALIDATOR
885
+ *
886
+ * Purpose: Validates if decimal places don't exceed specified limit
887
+ *
888
+ * @param val - Input string to validate
889
+ * @param dec - Maximum allowed decimal places
890
+ * @returns Boolean indicating if decimal places are within limit
891
+ *
892
+ * Key Features:
893
+ * - Handles strings without decimal points (always valid)
894
+ * - Counts decimal places after the decimal point
895
+ * - Used for form validation and precision control
896
+ *
897
+ * Examples:
898
+ * isDecimalValid("12.34", 2) → true
899
+ * isDecimalValid("12.345", 2) → false
900
+ * isDecimalValid("12", 2) → true
901
+ *
902
+ * Algorithm:
903
+ * 1. Convert input to string
904
+ * 2. Check if decimal point exists
905
+ * 3. If exists, count characters after decimal point
906
+ * 4. Compare against maximum allowed
907
+ */
484
908
  var _isDecimalValid = function isDecimalValid(val, dec) {
485
909
  var stringVal = val.toString();
486
- return stringVal.indexOf('.') >= 0 ? !(stringVal.split('.')[1].length > dec) : true;
910
+ // If no decimal point, any number of allowed decimals is valid
911
+ return stringVal.indexOf('.') >= 0 ? !(stringVal.split('.')[1].length > dec) // Check decimal places
912
+ : true; // No decimal point = valid
913
+ };
914
+ // ============================================================================
915
+ // ENHANCED MATHEMATICAL OPERATIONS SUITE
916
+ // ============================================================================
917
+ /**
918
+ * SAFE MATHEMATICAL OPERATIONS OBJECT
919
+ *
920
+ * Purpose: Provides a complete suite of mathematical operations using bigDecimal
921
+ *
922
+ * Key Features:
923
+ * - All operations use safeNumber() conversion
924
+ * - Returns string results to prevent scientific notation
925
+ * - Consistent API across all operations
926
+ * - High precision calculations
927
+ *
928
+ * Available Operations:
929
+ * - add: Addition with precision
930
+ * - subtract: Subtraction with precision
931
+ * - multiply: Multiplication with precision
932
+ * - divide: Division with configurable precision
933
+ *
934
+ * Usage:
935
+ * safeMath.add(1e-8, 2e-8) → "0.00000003"
936
+ * safeMath.multiply("1.5", "2.3") → "3.45"
937
+ */
938
+ var safeMath = {
939
+ /**
940
+ * SAFE ADDITION
941
+ * @param num1 - First addend
942
+ * @param num2 - Second addend
943
+ * @returns Sum as decimal string
944
+ */
945
+ add: function add(num1, num2) {
946
+ return bigDecimal.add(safeNumber(num1), safeNumber(num2));
947
+ },
948
+ /**
949
+ * SAFE SUBTRACTION
950
+ * @param num1 - Minuend (number to subtract from)
951
+ * @param num2 - Subtrahend (number to subtract)
952
+ * @returns Difference as decimal string
953
+ */
954
+ subtract: function subtract(num1, num2) {
955
+ return bigDecimal.subtract(safeNumber(num1), safeNumber(num2));
956
+ },
957
+ /**
958
+ * SAFE MULTIPLICATION
959
+ * @param num1 - First factor
960
+ * @param num2 - Second factor
961
+ * @returns Product as decimal string
962
+ */
963
+ multiply: function multiply(num1, num2) {
964
+ return bigDecimal.multiply(safeNumber(num1), safeNumber(num2));
965
+ },
966
+ /**
967
+ * SAFE DIVISION
968
+ * @param num1 - Dividend
969
+ * @param num2 - Divisor
970
+ * @param precision - Decimal places in result (default: 10)
971
+ * @returns Quotient as decimal string
972
+ */
973
+ divide: function divide(num1, num2, precision) {
974
+ if (precision === void 0) {
975
+ precision = 10;
976
+ }
977
+ return _divide(num1, num2, precision);
978
+ }
487
979
  };
980
+ // ============================================================================
981
+ // MAIN EXPORT OBJECT - COMPLETE API
982
+ // ============================================================================
983
+ /**
984
+ * COMPREHENSIVE NUMBER UTILITIES EXPORT
985
+ *
986
+ * This object provides the complete API for all number operations, formatting,
987
+ * validation, and mathematical calculations. All functions are designed to
988
+ * prevent scientific notation and maintain high precision.
989
+ *
990
+ * Categories:
991
+ * 1. Formatting: delimiter, removeDelimiter, suffix
992
+ * 2. Rounding: roundUp, roundDown
993
+ * 3. Validation: isValid, isDecimalValid
994
+ * 4. Conversion: toEn, convertScientific, safeNumber
995
+ * 5. Mathematics: All bigDecimal operations + safeMath suite
996
+ * 6. Utilities: Direct access to bigDecimal library
997
+ */
488
998
  var numberUtils = {
999
+ // ============================================================================
1000
+ // FORMATTING & DISPLAY FUNCTIONS
1001
+ // ============================================================================
1002
+ /**
1003
+ * Add thousand separators to numbers
1004
+ * Usage: delimiter(1234567) → "1,234,567"
1005
+ */
489
1006
  delimiter: function delimiter(num, separator, separateBy) {
490
1007
  return _delimiter(num, separator, separateBy);
491
1008
  },
1009
+ /**
1010
+ * Remove thousand separators from formatted strings
1011
+ * Usage: removeDelimiter("1,234,567") → "1234567"
1012
+ */
492
1013
  removeDelimiter: function removeDelimiter(num, separator) {
493
1014
  if (separator === void 0) {
494
1015
  separator = ',';
495
1016
  }
496
1017
  return _removeDelimiter(num, separator);
497
1018
  },
1019
+ /**
1020
+ * Format large numbers with K/M/B/T suffixes
1021
+ * Usage: suffix(1000000) → "1M"
1022
+ */
1023
+ suffix: suffix,
1024
+ // ============================================================================
1025
+ // ROUNDING FUNCTIONS
1026
+ // ============================================================================
1027
+ /**
1028
+ * Round number down to specified decimal places
1029
+ * Usage: roundDown(3.14159, 2) → "3.14"
1030
+ */
498
1031
  roundDown: function roundDown(val, dec) {
499
1032
  return _roundDown(val, dec);
500
1033
  },
1034
+ /**
1035
+ * Round number up to specified decimal places
1036
+ * Usage: roundUp(3.14159, 2) → "3.15"
1037
+ */
501
1038
  roundUp: function roundUp(val, dec) {
502
1039
  return _roundUp(val, dec);
503
1040
  },
1041
+ // ============================================================================
1042
+ // VALIDATION FUNCTIONS
1043
+ // ============================================================================
1044
+ /**
1045
+ * Validate if decimal places are within specified limit
1046
+ * Usage: isDecimalValid("12.34", 2) → true
1047
+ */
504
1048
  isDecimalValid: function isDecimalValid(val, dec) {
505
1049
  return _isDecimalValid(val, dec);
506
1050
  },
1051
+ /**
1052
+ * Validate if input contains only valid numeric characters
1053
+ * Usage: isValid("123.45") → true
1054
+ */
507
1055
  isValid: function isValid(val) {
508
1056
  return _isValid(val);
509
1057
  },
1058
+ // ============================================================================
1059
+ // CONVERSION & UTILITY FUNCTIONS
1060
+ // ============================================================================
1061
+ /**
1062
+ * Convert Persian numerals to English numerals
1063
+ * Usage: toEn("۱۲۳") → "123"
1064
+ */
510
1065
  toEn: function toEn(val) {
511
1066
  return _toEn(val);
512
1067
  },
513
- suffix: suffix,
1068
+ /**
1069
+ * Convert scientific notation to decimal string
1070
+ * Usage: convertScientific(1e-8) → "0.00000001"
1071
+ */
1072
+ convertScientific: convertScientific,
1073
+ /**
1074
+ * Safe number conversion with fallback to "0"
1075
+ * Usage: safeNumber(1e-8) → "0.00000001"
1076
+ */
1077
+ safeNumber: safeNumber,
1078
+ // ============================================================================
1079
+ // ENHANCED MATHEMATICAL OPERATIONS
1080
+ // ============================================================================
1081
+ /**
1082
+ * Complete suite of safe mathematical operations
1083
+ * All operations prevent scientific notation and maintain precision
1084
+ */
1085
+ safeMath: safeMath,
1086
+ /**
1087
+ * Direct access to bigDecimal library for advanced operations
1088
+ */
514
1089
  bigDecimal: bigDecimal,
515
- modulus: bigDecimal.modulus,
516
- divide: divide,
517
- multiply: bigDecimal.multiply,
518
- subtract: bigDecimal.subtract,
519
- add: bigDecimal.add,
520
- negate: bigDecimal.negate,
521
- compareTo: bigDecimal.compareTo,
522
- ceil: bigDecimal.ceil,
523
- floor: bigDecimal.floor,
524
- abs: bigDecimal.abs,
525
- round: bigDecimal.round,
526
- getPrettyValue: bigDecimal.getPrettyValue
1090
+ // ============================================================================
1091
+ // INDIVIDUAL MATHEMATICAL OPERATIONS (Enhanced with safeNumber)
1092
+ // ============================================================================
1093
+ /**
1094
+ * Modulus operation with precision
1095
+ * Usage: modulus(10, 3) → remainder as string
1096
+ */
1097
+ modulus: function modulus(num1, num2) {
1098
+ return bigDecimal.modulus(safeNumber(num1), safeNumber(num2));
1099
+ },
1100
+ /**
1101
+ * Division with configurable precision
1102
+ * Usage: divide(10, 3, 4) → "3.3333"
1103
+ */
1104
+ divide: _divide,
1105
+ /**
1106
+ * Multiplication with precision
1107
+ * Usage: multiply(1.5, 2.3) → "3.45"
1108
+ */
1109
+ multiply: function multiply(num1, num2) {
1110
+ return bigDecimal.multiply(safeNumber(num1), safeNumber(num2));
1111
+ },
1112
+ /**
1113
+ * Subtraction with precision
1114
+ * Usage: subtract(10, 3.5) → "6.5"
1115
+ */
1116
+ subtract: function subtract(num1, num2) {
1117
+ return bigDecimal.subtract(safeNumber(num1), safeNumber(num2));
1118
+ },
1119
+ /**
1120
+ * Addition with precision
1121
+ * Usage: add(1.1, 2.2) → "3.3"
1122
+ */
1123
+ add: function add(num1, num2) {
1124
+ return bigDecimal.add(safeNumber(num1), safeNumber(num2));
1125
+ },
1126
+ /**
1127
+ * Number negation
1128
+ * Usage: negate(5) → "-5"
1129
+ */
1130
+ negate: function negate(num) {
1131
+ return bigDecimal.negate(safeNumber(num));
1132
+ },
1133
+ /**
1134
+ * Number comparison (-1: less, 0: equal, 1: greater)
1135
+ * Usage: compareTo(5, 3) → 1
1136
+ */
1137
+ compareTo: function compareTo(num1, num2) {
1138
+ return bigDecimal.compareTo(safeNumber(num1), safeNumber(num2));
1139
+ },
1140
+ /**
1141
+ * Ceiling function (round up to nearest integer)
1142
+ * Usage: ceil(3.14) → "4"
1143
+ */
1144
+ ceil: function ceil(num) {
1145
+ return bigDecimal.ceil(safeNumber(num));
1146
+ },
1147
+ /**
1148
+ * Floor function (round down to nearest integer)
1149
+ * Usage: floor(3.14) → "3"
1150
+ */
1151
+ floor: function floor(num) {
1152
+ return bigDecimal.floor(safeNumber(num));
1153
+ },
1154
+ /**
1155
+ * Absolute value
1156
+ * Usage: abs(-5) → "5"
1157
+ */
1158
+ abs: function abs(num) {
1159
+ return bigDecimal.abs(safeNumber(num));
1160
+ },
1161
+ /**
1162
+ * Round to specified precision
1163
+ * Usage: round(3.14159, 2) → "3.14"
1164
+ */
1165
+ round: function round(num, precision) {
1166
+ return bigDecimal.round(safeNumber(num), precision);
1167
+ },
1168
+ /**
1169
+ * Format number with pretty printing (thousands separators)
1170
+ * Usage: getPrettyValue(1234567, 2, ",") → "1,234,567.00"
1171
+ */
1172
+ getPrettyValue: function getPrettyValue(num, precision, separator) {
1173
+ return bigDecimal.getPrettyValue(safeNumber(num), precision, separator);
1174
+ }
527
1175
  };
528
1176
 
529
1177
  var handleSearch = function handleSearch(list, value) {