@dravishek/number-validate 1.0.4 → 1.1.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.
package/README.md CHANGED
@@ -45,6 +45,8 @@ export class AppModule { }
45
45
 
46
46
  ## Usage
47
47
 
48
+ ### Accepting both positive & negative numbers (including 0)
49
+
48
50
  - For decimal numbers
49
51
 
50
52
  ```html
@@ -57,6 +59,34 @@ export class AppModule { }
57
59
  <input type="text" adrNumberValidate="2" />
58
60
  ```
59
61
 
62
+ ### Accepting only positive numbers (including 0)
63
+
64
+ - For decimal numbers
65
+
66
+ ```html
67
+ <input type="text" adrNumberValidate="+2.5" />
68
+ ```
69
+
70
+ - For non decimal numbers
71
+
72
+ ```html
73
+ <input type="text" adrNumberValidate="+2" />
74
+ ```
75
+
76
+ ### Accepting only negative numbers (excluding 0)
77
+
78
+ - For decimal numbers
79
+
80
+ ```html
81
+ <input type="text" adrNumberValidate="-2.5" />
82
+ ```
83
+
84
+ - For non decimal numbers
85
+
86
+ ```html
87
+ <input type="text" adrNumberValidate="-2" />
88
+ ```
89
+
60
90
  ## Social
61
91
 
62
92
  [![@barefacedbear](https://skillicons.dev/icons?i=github)](https://github.com/barefacedbear)
@@ -25,33 +25,93 @@ class AdrNumberValidateDirective {
25
25
  this.previousValue = currentValue;
26
26
  }
27
27
  }
28
+ /**
29
+ * Validates the input string against a dynamically constructed regular expression
30
+ * based on the ADR number format specification.
31
+ *
32
+ * The format is determined by splitting the result of `adrNumberValidate()` into
33
+ * a prefix and scale. The prefix is used to extract the allowed sign and digit length,
34
+ * while the scale determines the number of digits allowed after the decimal point.
35
+ *
36
+ * @param value - The input string to validate.
37
+ * @returns A `RegExpMatchArray` if the input matches the constructed regular expression,
38
+ * or `null` if it does not match.
39
+ */
28
40
  checkValue(value) {
29
- const [prefix, scale] = this.adrNumberValidate().split('.'), PREFIX_DETAIL = this.extractSignWithLength(prefix);
30
- let regExpString = `^(${PREFIX_DETAIL.symbol})?([\\d]{0,${PREFIX_DETAIL.prefix}})`, checkPattern = null;
41
+ const [prefix, scale] = this.adrNumberValidate().split('.'), { regex, prefix: maxDigitsBeforeDecimal } = this.extractSignWithLength(prefix);
42
+ let regExpString = `^(${regex}{1,${maxDigitsBeforeDecimal}})`;
31
43
  if (+scale > 0) {
32
- regExpString += `((\\.{1})([\\d]{1,${+scale}})?)`;
44
+ regExpString += `(\\.{1}[\\d]{0,${+scale}})?`;
33
45
  }
34
- checkPattern = String(value).match(new RegExp(`${regExpString}?$`));
35
- return checkPattern;
46
+ const fullRegex = new RegExp(`${regExpString}$`);
47
+ return value.match(fullRegex);
36
48
  }
49
+ /**
50
+ * Extracts the sign and digit length from a given prefix string and generates a corresponding regex pattern.
51
+ *
52
+ * The prefix should be in the format of an optional sign ('-' or '+') followed by one or more digits (e.g., "-3", "+2", "5").
53
+ * The function returns an object containing:
54
+ * - `regex`: A string representing the regex pattern for the sign and digit.
55
+ * - `prefix`: The number of digits specified in the prefix.
56
+ *
57
+ * If the prefix does not match the expected format, a default regex pattern and prefix value are returned.
58
+ *
59
+ * @param prefix - The string containing an optional sign and digit count.
60
+ * @returns An object with `regex` (string) and `prefix` (number) properties.
61
+ */
37
62
  extractSignWithLength(prefix) {
38
- const char = prefix.charAt(0);
39
- if (char) {
40
- const sign = { '+': '\\+', '-': '\\-' }, symbol = sign[char] ?? '\\+|\\-', firstChar = +(sign[char] ? prefix[1] : prefix[0]);
41
- return { symbol, prefix: firstChar };
63
+ const signMatch = prefix.match(/^([-+]?)(\d+)$/);
64
+ if (signMatch) {
65
+ const sign = signMatch[1]; // "-" or "+"
66
+ const digitCount = +signMatch[2];
67
+ // Enforce mandatory sign if specified
68
+ let signRegex = '';
69
+ const signRegexMap = { '-': '\\-', '+': '\\+?' };
70
+ signRegex = signRegexMap[sign] ?? '[-+]?';
71
+ return { regex: `${signRegex}\\d`, prefix: digitCount };
42
72
  }
43
- return { symbol: '\\+|\\-', prefix: 0 };
73
+ return { regex: '[-+]?\\d', prefix: 0 };
44
74
  }
75
+ /**
76
+ * Handles input validation and value patching for ADR number fields.
77
+ *
78
+ * This method enforces sign rules based on the validation pattern:
79
+ * - If a negative sign is required, the value must start with '-'.
80
+ * - If a positive sign is required, the value must not start with '-'.
81
+ * - If no sign is required, any value is allowed.
82
+ *
83
+ * The method allows intermediate input states (e.g., "-", "-.", "-12.") to support user typing.
84
+ * If the input does not meet the required sign rules or is invalid, it reverts to the previous value.
85
+ * Otherwise, it patches the control value with the parsed number or the current string value,
86
+ * preserving intermediate states and empty input.
87
+ *
88
+ * @param oldValue - The previous valid value of the input, used to revert in case of invalid input.
89
+ */
45
90
  execute(oldValue) {
46
91
  setTimeout(() => {
47
- let currentValue = this.el.nativeElement.value;
48
- if (currentValue && !this.checkValue(currentValue)) {
49
- this.control?.control && this.control.control.patchValue(+oldValue);
50
- this.el.nativeElement.value = +oldValue;
92
+ const inputElement = this.el.nativeElement, currentValue = inputElement.value, pattern = this.adrNumberValidate(), requiresNegative = pattern.startsWith('-'), requiresPositive = pattern.startsWith('+');
93
+ // Enforce sign rules:
94
+ // - If negative is required, must start with '-'
95
+ // - If positive is required, must NOT start with '-' (but '+' is optional)
96
+ const hasRequiredSign = (!requiresNegative && !requiresPositive) ||
97
+ (requiresNegative && currentValue.startsWith('-')) ||
98
+ (requiresPositive && !currentValue.startsWith('-'));
99
+ // If the sign is missing and required, reject immediately
100
+ if (!hasRequiredSign && currentValue !== '') {
101
+ this.control?.control?.patchValue(0);
102
+ inputElement.value = '';
103
+ return;
104
+ }
105
+ // Allow intermediate states like "-", "-.", "-12.", etc.
106
+ const isIntermediate = /^-?$|^\.$|^-?\.$|^-?\d+\.$|^\d+\.$/.test(currentValue), isValid = this.checkValue(currentValue);
107
+ if (currentValue === '' || isValid || isIntermediate) {
108
+ this.previousValue = currentValue;
109
+ const endsWithDot = currentValue.endsWith('.'), patchValue = currentValue === '' ? '' : (!endsWithDot && !isNaN(+currentValue)) ? +currentValue : currentValue;
110
+ this.control?.control?.patchValue(patchValue);
51
111
  }
52
112
  else {
53
- this.control?.control && this.control.control.patchValue(+currentValue);
54
- this.el.nativeElement.value = currentValue && !isNaN(+currentValue) ? +currentValue : '';
113
+ inputElement.value = oldValue;
114
+ this.control?.control?.patchValue(isNaN(+oldValue) ? oldValue : +oldValue);
55
115
  }
56
116
  });
57
117
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dravishek-number-validate.mjs","sources":["../../../../projects/dravishek/number-validate/src/lib/adr-number-validate.directive.ts","../../../../projects/dravishek/number-validate/src/public-api.ts","../../../../projects/dravishek/number-validate/src/dravishek-number-validate.ts"],"sourcesContent":["import { Directive, DoCheck, ElementRef, HostListener, input, Optional } from '@angular/core';\r\nimport { NgControl } from '@angular/forms';\r\n\r\n@Directive({\r\n selector: '[adrNumberValidate]',\r\n standalone: true\r\n})\r\nexport class AdrNumberValidateDirective implements DoCheck {\r\n\r\n constructor(private el: ElementRef, @Optional() private control: NgControl) { }\r\n\r\n /**\r\n * @description Value before the decimal point specifies the number of digits before decimal and value after the decimal specifies the number of digits after decimal.\r\n * Example: 7.3 (Before decimal 7 digits & 3 digits after decimal)\r\n * Possible type of patterns allowed: X, X.X\r\n */\r\n adrNumberValidate = input<string>('');\r\n private previousValue: string = '';\r\n\r\n @HostListener(\"keydown\", [\"$event\"])\r\n onKeyDown = (event: KeyboardEvent) => this.execute(this.el.nativeElement.value);\r\n\r\n @HostListener(\"paste\", [\"$event\"])\r\n onPaste = (event: ClipboardEvent) => this.execute(this.el.nativeElement.value);\r\n\r\n ngDoCheck(): void {\r\n const currentValue = this.el.nativeElement.value;\r\n if (currentValue !== this.previousValue) {\r\n this.execute(this.previousValue);\r\n this.previousValue = currentValue;\r\n }\r\n }\r\n\r\n private checkValue(value: string): RegExpMatchArray | null {\r\n const [prefix, scale] = this.adrNumberValidate().split('.'), PREFIX_DETAIL = this.extractSignWithLength(prefix);\r\n let regExpString = `^(${PREFIX_DETAIL.symbol})?([\\\\d]{0,${PREFIX_DETAIL.prefix}})`, checkPattern: RegExpMatchArray | null = null;\r\n if (+scale > 0) { regExpString += `((\\\\.{1})([\\\\d]{1,${+scale}})?)` }\r\n checkPattern = String(value).match(new RegExp(`${regExpString}?$`));\r\n return checkPattern;\r\n }\r\n\r\n private extractSignWithLength(prefix: string) {\r\n const char = prefix.charAt(0);\r\n if (char) {\r\n const sign: Record<string, string> = { '+': '\\\\+', '-': '\\\\-' }, symbol = sign[char] ?? '\\\\+|\\\\-', firstChar = +(sign[char] ? prefix[1] : prefix[0]);\r\n return { symbol, prefix: firstChar };\r\n }\r\n return { symbol: '\\\\+|\\\\-', prefix: 0 };\r\n }\r\n\r\n private execute(oldValue: string) {\r\n setTimeout(() => {\r\n let currentValue: string = this.el.nativeElement.value;\r\n if (currentValue && !this.checkValue(currentValue)) {\r\n this.control?.control && this.control.control.patchValue(+oldValue);\r\n this.el.nativeElement.value = +oldValue;\r\n } else {\r\n this.control?.control && this.control.control.patchValue(+currentValue);\r\n this.el.nativeElement.value = currentValue && !isNaN(+currentValue) ? +currentValue : '';\r\n }\r\n });\r\n }\r\n}\r\n","/*\r\n * Public API Surface of number-validate\r\n */\r\n\r\nexport * from './lib/adr-number-validate.directive';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dravishek-number-validate.mjs","sources":["../../../../projects/dravishek/number-validate/src/lib/adr-number-validate.directive.ts","../../../../projects/dravishek/number-validate/src/public-api.ts","../../../../projects/dravishek/number-validate/src/dravishek-number-validate.ts"],"sourcesContent":["import { Directive, DoCheck, ElementRef, HostListener, input, Optional } from '@angular/core';\r\nimport { NgControl } from '@angular/forms';\r\n\r\n@Directive({\r\n selector: '[adrNumberValidate]',\r\n standalone: true\r\n})\r\nexport class AdrNumberValidateDirective implements DoCheck {\r\n\r\n constructor(private el: ElementRef, @Optional() private control: NgControl) { }\r\n\r\n /**\r\n * @description Value before the decimal point specifies the number of digits before decimal and value after the decimal specifies the number of digits after decimal.\r\n * Example: 7.3 (Before decimal 7 digits & 3 digits after decimal)\r\n * Possible type of patterns allowed: X, X.X\r\n */\r\n adrNumberValidate = input<string>('');\r\n private previousValue: string = '';\r\n\r\n @HostListener(\"keydown\", [\"$event\"])\r\n onKeyDown = (event: KeyboardEvent) => this.execute(this.el.nativeElement.value);\r\n\r\n @HostListener(\"paste\", [\"$event\"])\r\n onPaste = (event: ClipboardEvent) => this.execute(this.el.nativeElement.value);\r\n\r\n ngDoCheck(): void {\r\n const currentValue = this.el.nativeElement.value;\r\n if (currentValue !== this.previousValue) {\r\n this.execute(this.previousValue);\r\n this.previousValue = currentValue;\r\n }\r\n }\r\n\r\n /**\r\n * Validates the input string against a dynamically constructed regular expression\r\n * based on the ADR number format specification.\r\n *\r\n * The format is determined by splitting the result of `adrNumberValidate()` into\r\n * a prefix and scale. The prefix is used to extract the allowed sign and digit length,\r\n * while the scale determines the number of digits allowed after the decimal point.\r\n *\r\n * @param value - The input string to validate.\r\n * @returns A `RegExpMatchArray` if the input matches the constructed regular expression,\r\n * or `null` if it does not match.\r\n */\r\n private checkValue(value: string): RegExpMatchArray | null {\r\n const [prefix, scale] = this.adrNumberValidate().split('.'), { regex, prefix: maxDigitsBeforeDecimal } = this.extractSignWithLength(prefix);\r\n let regExpString = `^(${regex}{1,${maxDigitsBeforeDecimal}})`;\r\n if (+scale > 0) {\r\n regExpString += `(\\\\.{1}[\\\\d]{0,${+scale}})?`;\r\n }\r\n const fullRegex = new RegExp(`${regExpString}$`);\r\n return value.match(fullRegex);\r\n }\r\n\r\n /**\r\n * Extracts the sign and digit length from a given prefix string and generates a corresponding regex pattern.\r\n *\r\n * The prefix should be in the format of an optional sign ('-' or '+') followed by one or more digits (e.g., \"-3\", \"+2\", \"5\").\r\n * The function returns an object containing:\r\n * - `regex`: A string representing the regex pattern for the sign and digit.\r\n * - `prefix`: The number of digits specified in the prefix.\r\n *\r\n * If the prefix does not match the expected format, a default regex pattern and prefix value are returned.\r\n *\r\n * @param prefix - The string containing an optional sign and digit count.\r\n * @returns An object with `regex` (string) and `prefix` (number) properties.\r\n */\r\n private extractSignWithLength(prefix: string) {\r\n const signMatch = prefix.match(/^([-+]?)(\\d+)$/);\r\n if (signMatch) {\r\n const sign = signMatch[1]; // \"-\" or \"+\"\r\n const digitCount = +signMatch[2];\r\n // Enforce mandatory sign if specified\r\n let signRegex = '';\r\n const signRegexMap: { [key: string]: string } = { '-': '\\\\-', '+': '\\\\+?' };\r\n signRegex = signRegexMap[sign] ?? '[-+]?';\r\n return { regex: `${signRegex}\\\\d`, prefix: digitCount };\r\n }\r\n return { regex: '[-+]?\\\\d', prefix: 0 };\r\n }\r\n\r\n /**\r\n * Handles input validation and value patching for ADR number fields.\r\n *\r\n * This method enforces sign rules based on the validation pattern:\r\n * - If a negative sign is required, the value must start with '-'.\r\n * - If a positive sign is required, the value must not start with '-'.\r\n * - If no sign is required, any value is allowed.\r\n *\r\n * The method allows intermediate input states (e.g., \"-\", \"-.\", \"-12.\") to support user typing.\r\n * If the input does not meet the required sign rules or is invalid, it reverts to the previous value.\r\n * Otherwise, it patches the control value with the parsed number or the current string value,\r\n * preserving intermediate states and empty input.\r\n *\r\n * @param oldValue - The previous valid value of the input, used to revert in case of invalid input.\r\n */\r\n private execute(oldValue: string) {\r\n setTimeout(() => {\r\n const inputElement = this.el.nativeElement as HTMLInputElement, currentValue: string = inputElement.value,\r\n pattern = this.adrNumberValidate(), requiresNegative = pattern.startsWith('-'), requiresPositive = pattern.startsWith('+');\r\n // Enforce sign rules:\r\n // - If negative is required, must start with '-'\r\n // - If positive is required, must NOT start with '-' (but '+' is optional)\r\n const hasRequiredSign =\r\n (!requiresNegative && !requiresPositive) ||\r\n (requiresNegative && currentValue.startsWith('-')) ||\r\n (requiresPositive && !currentValue.startsWith('-'));\r\n // If the sign is missing and required, reject immediately\r\n if (!hasRequiredSign && currentValue !== '') {\r\n this.control?.control?.patchValue(0);\r\n inputElement.value = '';\r\n return;\r\n }\r\n // Allow intermediate states like \"-\", \"-.\", \"-12.\", etc.\r\n const isIntermediate = /^-?$|^\\.$|^-?\\.$|^-?\\d+\\.$|^\\d+\\.$/.test(currentValue), isValid = this.checkValue(currentValue);\r\n if (currentValue === '' || isValid || isIntermediate) {\r\n this.previousValue = currentValue;\r\n const endsWithDot = currentValue.endsWith('.'),\r\n patchValue = currentValue === '' ? '' : (!endsWithDot && !isNaN(+currentValue)) ? +currentValue : currentValue;\r\n this.control?.control?.patchValue(patchValue);\r\n } else {\r\n inputElement.value = oldValue;\r\n this.control?.control?.patchValue(isNaN(+oldValue) ? oldValue : +oldValue);\r\n }\r\n });\r\n }\r\n}\r\n","/*\r\n * Public API Surface of number-validate\r\n */\r\n\r\nexport * from './lib/adr-number-validate.directive';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -15,8 +15,48 @@ export declare class AdrNumberValidateDirective implements DoCheck {
15
15
  onKeyDown: (event: KeyboardEvent) => void;
16
16
  onPaste: (event: ClipboardEvent) => void;
17
17
  ngDoCheck(): void;
18
+ /**
19
+ * Validates the input string against a dynamically constructed regular expression
20
+ * based on the ADR number format specification.
21
+ *
22
+ * The format is determined by splitting the result of `adrNumberValidate()` into
23
+ * a prefix and scale. The prefix is used to extract the allowed sign and digit length,
24
+ * while the scale determines the number of digits allowed after the decimal point.
25
+ *
26
+ * @param value - The input string to validate.
27
+ * @returns A `RegExpMatchArray` if the input matches the constructed regular expression,
28
+ * or `null` if it does not match.
29
+ */
18
30
  private checkValue;
31
+ /**
32
+ * Extracts the sign and digit length from a given prefix string and generates a corresponding regex pattern.
33
+ *
34
+ * The prefix should be in the format of an optional sign ('-' or '+') followed by one or more digits (e.g., "-3", "+2", "5").
35
+ * The function returns an object containing:
36
+ * - `regex`: A string representing the regex pattern for the sign and digit.
37
+ * - `prefix`: The number of digits specified in the prefix.
38
+ *
39
+ * If the prefix does not match the expected format, a default regex pattern and prefix value are returned.
40
+ *
41
+ * @param prefix - The string containing an optional sign and digit count.
42
+ * @returns An object with `regex` (string) and `prefix` (number) properties.
43
+ */
19
44
  private extractSignWithLength;
45
+ /**
46
+ * Handles input validation and value patching for ADR number fields.
47
+ *
48
+ * This method enforces sign rules based on the validation pattern:
49
+ * - If a negative sign is required, the value must start with '-'.
50
+ * - If a positive sign is required, the value must not start with '-'.
51
+ * - If no sign is required, any value is allowed.
52
+ *
53
+ * The method allows intermediate input states (e.g., "-", "-.", "-12.") to support user typing.
54
+ * If the input does not meet the required sign rules or is invalid, it reverts to the previous value.
55
+ * Otherwise, it patches the control value with the parsed number or the current string value,
56
+ * preserving intermediate states and empty input.
57
+ *
58
+ * @param oldValue - The previous valid value of the input, used to revert in case of invalid input.
59
+ */
20
60
  private execute;
21
61
  static ɵfac: i0.ɵɵFactoryDeclaration<AdrNumberValidateDirective, [null, { optional: true; }]>;
22
62
  static ɵdir: i0.ɵɵDirectiveDeclaration<AdrNumberValidateDirective, "[adrNumberValidate]", never, { "adrNumberValidate": { "alias": "adrNumberValidate"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dravishek/number-validate",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "javascript",