@rubenpazch/numeric-up-picker 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"NumericUpPicker.d.ts","sourceRoot":"","sources":["../src/NumericUpPicker.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,KAAK,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,GAAG,EACH,GAAG,EACH,IAAW,EACX,KAAK,EACL,IAAI,EACJ,OAAO,EACP,QAAgB,EAChB,SAAc,EACd,QAAgB,EAChB,eAAuB,EACvB,cAAsB,EACtB,WAAmB,EACnB,QAAgB,EAChB,aAAqB,EACrB,SAAiB,EACjB,OAAO,GACR,EAAE,oBAAoB,2CAsXtB"}
1
+ {"version":3,"file":"NumericUpPicker.d.ts","sourceRoot":"","sources":["../src/NumericUpPicker.tsx"],"names":[],"mappings":"AAqBA,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,KAAK,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,GAAG,EACH,GAAG,EACH,IAAW,EACX,KAAK,EACL,IAAI,EACJ,OAAO,EACP,QAAgB,EAChB,SAAc,EACd,QAAgB,EAChB,eAAuB,EACvB,cAAsB,EACtB,WAAmB,EACnB,QAAgB,EAChB,aAAqB,EACrB,SAAiB,EACjB,OAAO,GACR,EAAE,oBAAoB,2CA6YtB"}
package/dist/index.cjs.js CHANGED
@@ -446,26 +446,33 @@ const hideSpinnersStyle = `
446
446
  -moz-appearance: textfield;
447
447
  }
448
448
  `;
449
- function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder, min, max, step = 0.01, error, hint, warning, disabled = false, className = '', required = false, useMinAsDefault = false, alwaysNegative = false, integerOnly = false, showSign = false, defaultToZero = false, clearable = false, onClear, }) {
449
+ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder, min, max, step = 0.01, error, hint, warning, disabled = false, className = "", required = false, useMinAsDefault = false, alwaysNegative = false, integerOnly = false, showSign = false, defaultToZero = false, clearable = false, onClear, }) {
450
450
  // Track if the field has been touched (user has focused on it)
451
451
  const [hasBeenTouched, setHasBeenTouched] = require$$0.useState(false);
452
- const numValue = typeof value === 'string' ? parseFloat(value) || 0 : value;
452
+ const numValue = typeof value === "string" ? parseFloat(value) || 0 : value;
453
453
  // Format display value with sign if showSign is true
454
454
  const displayValue = require$$0.useMemo(() => {
455
- if (!showSign || value === '' || value === '-' || value === null || value === undefined)
456
- return value || '';
455
+ if (!showSign ||
456
+ value === "" ||
457
+ value === "-" ||
458
+ value === null ||
459
+ value === undefined)
460
+ return value || "";
457
461
  const strValue = value.toString();
458
462
  const numVal = parseFloat(strValue);
459
463
  if (isNaN(numVal))
460
464
  return value;
461
- if (numVal > 0 && !strValue.startsWith('+')) {
465
+ if (numVal > 0 && !strValue.startsWith("+")) {
462
466
  return `+${strValue}`;
463
467
  }
464
468
  return value;
465
469
  }, [value, showSign]);
466
470
  const handleIncrement = () => {
467
471
  // If value is empty or invalid, start from 0 if defaultToZero, otherwise from min (or 0 if no min)
468
- if (value === '' || value === '-' || value === null || value === undefined) {
472
+ if (value === "" ||
473
+ value === "-" ||
474
+ value === null ||
475
+ value === undefined) {
469
476
  const startValue = defaultToZero ? 0 : min !== undefined ? min : 0;
470
477
  if (integerOnly) {
471
478
  onChange(Math.round(startValue).toString());
@@ -483,13 +490,18 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
483
490
  else {
484
491
  const formattedValue = newValue.toFixed(2);
485
492
  // If alwaysNegative, ensure the value has a negative sign
486
- onChange(alwaysNegative && newValue > 0 ? `-${formattedValue}` : formattedValue);
493
+ onChange(alwaysNegative && newValue > 0
494
+ ? `-${formattedValue}`
495
+ : formattedValue);
487
496
  }
488
497
  }
489
498
  };
490
499
  const handleDecrement = () => {
491
500
  // If value is empty or invalid, start from 0 if defaultToZero, otherwise from max (or 0 if no max)
492
- if (value === '' || value === '-' || value === null || value === undefined) {
501
+ if (value === "" ||
502
+ value === "-" ||
503
+ value === null ||
504
+ value === undefined) {
493
505
  const startValue = defaultToZero ? 0 : max !== undefined ? max : 0;
494
506
  if (integerOnly) {
495
507
  onChange(Math.round(startValue).toString());
@@ -516,11 +528,11 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
516
528
  };
517
529
  const handleKeyDown = (e) => {
518
530
  // Handle arrow up/down keys for incrementing/decrementing
519
- if (e.key === 'ArrowUp') {
531
+ if (e.key === "ArrowUp") {
520
532
  e.preventDefault(); // Prevent cursor movement
521
533
  handleIncrement();
522
534
  }
523
- else if (e.key === 'ArrowDown') {
535
+ else if (e.key === "ArrowDown") {
524
536
  e.preventDefault(); // Prevent cursor movement
525
537
  handleDecrement();
526
538
  }
@@ -536,22 +548,22 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
536
548
  let inputValue = e.target.value;
537
549
  // For showSign, remove the plus sign before processing
538
550
  if (showSign) {
539
- inputValue = inputValue.replace(/^\+/, '');
551
+ inputValue = inputValue.replace(/^\+/, "");
540
552
  }
541
553
  // For alwaysNegative fields, ensure value always starts with minus sign
542
554
  if (alwaysNegative) {
543
555
  // Remove any existing minus signs
544
- inputValue = inputValue.replace(/-/g, '');
556
+ inputValue = inputValue.replace(/-/g, "");
545
557
  // Allow empty input
546
- if (inputValue === '') {
547
- onChange('-');
558
+ if (inputValue === "") {
559
+ onChange("-");
548
560
  return;
549
561
  }
550
562
  // Add minus sign at the beginning
551
563
  inputValue = `-${inputValue}`;
552
564
  }
553
565
  // Allow empty input (user deleted content)
554
- if (inputValue === '' || inputValue === '-') {
566
+ if (inputValue === "" || inputValue === "-") {
555
567
  onChange(inputValue);
556
568
  return;
557
569
  }
@@ -559,16 +571,16 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
559
571
  onChange(inputValue);
560
572
  };
561
573
  const handleClear = () => {
562
- onChange('');
574
+ onChange("");
563
575
  onClear?.();
564
576
  };
565
577
  const handleBlurWithValidation = () => {
566
578
  const inputValue = value.toString();
567
579
  // If empty, handle based on required and useMinAsDefault flags
568
- if (inputValue === '' || inputValue === '-') {
580
+ if (inputValue === "" || inputValue === "-") {
569
581
  // For optional fields (!required), allow empty values
570
582
  if (!required) {
571
- onChange('');
583
+ onChange("");
572
584
  onBlur?.();
573
585
  return;
574
586
  }
@@ -594,17 +606,17 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
594
606
  }
595
607
  else if (!hasBeenTouched) {
596
608
  // If never touched, keep it empty
597
- onChange('');
609
+ onChange("");
598
610
  }
599
611
  else {
600
- onChange(integerOnly ? '0' : alwaysNegative ? '-0.00' : '0.00');
612
+ onChange(integerOnly ? "0" : alwaysNegative ? "-0.00" : "0.00");
601
613
  }
602
614
  onBlur?.();
603
615
  return;
604
616
  }
605
617
  // Parse the input value (remove negative sign if present for alwaysNegative fields)
606
618
  let numericValue = alwaysNegative
607
- ? parseFloat(inputValue.replace(/^-/, ''))
619
+ ? parseFloat(inputValue.replace(/^-/, ""))
608
620
  : parseFloat(inputValue);
609
621
  // If not a valid number, reset to min or 0
610
622
  if (isNaN(numericValue)) {
@@ -627,7 +639,7 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
627
639
  }
628
640
  }
629
641
  else {
630
- onChange(integerOnly ? '0' : alwaysNegative ? '-0.00' : '0.00');
642
+ onChange(integerOnly ? "0" : alwaysNegative ? "-0.00" : "0.00");
631
643
  }
632
644
  onBlur?.();
633
645
  return;
@@ -672,7 +684,7 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
672
684
  };
673
685
  // Disable buttons only if value is not empty and at min/max
674
686
  // When value is empty, allow both buttons (they will set to min/max)
675
- const isEmpty = value === '' || value === '-' || value === null || value === undefined;
687
+ const isEmpty = value === "" || value === "-" || value === null || value === undefined;
676
688
  // For alwaysNegative fields, we compare absolute values
677
689
  const isAtMin = !isEmpty &&
678
690
  (alwaysNegative
@@ -682,23 +694,23 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
682
694
  (alwaysNegative
683
695
  ? max !== undefined && Math.abs(numValue) <= Math.abs(max)
684
696
  : max !== undefined && numValue >= max);
685
- return (jsxRuntimeExports.jsxs("div", { className: className, children: [jsxRuntimeExports.jsx("style", { children: hideSpinnersStyle }), label && (jsxRuntimeExports.jsxs("label", { className: `block text-sm font-medium mb-2 ${error ? 'text-red-700' : 'text-gray-700'}`, children: [label, required && jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })] })), jsxRuntimeExports.jsxs("div", { className: `flex items-center justify-between h-12 rounded-lg border-2 transition-all ${error
686
- ? 'border-red-500 bg-red-50'
697
+ return (jsxRuntimeExports.jsxs("div", { className: className, children: [jsxRuntimeExports.jsx("style", { children: hideSpinnersStyle }), label && (jsxRuntimeExports.jsxs("label", { className: `block text-sm font-medium mb-2 ${error ? "text-red-700" : "text-gray-700"}`, children: [label, required && jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })] })), jsxRuntimeExports.jsxs("div", { className: `flex items-center justify-between h-12 rounded-lg border-2 transition-all ${error
698
+ ? "border-red-500 bg-red-50"
687
699
  : disabled
688
- ? 'border-gray-300 bg-gray-100 opacity-50 cursor-not-allowed'
689
- : 'border-gray-300 bg-gray-50'}`, children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: handleDecrement, disabled: disabled || isAtMin, className: `flex-shrink-0 w-12 h-full flex items-center justify-center border-r border-gray-300 transition-all ${error
690
- ? 'text-red-500'
700
+ ? "border-gray-300 bg-gray-100 opacity-50 cursor-not-allowed"
701
+ : "border-gray-300 bg-gray-50"}`, children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: handleDecrement, disabled: disabled || isAtMin, className: `flex-shrink-0 w-12 h-full flex items-center justify-center border-r border-gray-300 transition-all ${error
702
+ ? "text-red-500"
691
703
  : disabled || isAtMin
692
- ? 'opacity-40 cursor-not-allowed text-gray-400'
693
- : 'hover:bg-gray-100 active:bg-gray-200 text-gray-600'}`, title: "Decrease value", "aria-label": "Decrease", children: jsxRuntimeExports.jsx(R, { size: "md" }) }), jsxRuntimeExports.jsxs("div", { className: "flex-1 flex items-center justify-center relative", children: [jsxRuntimeExports.jsx("input", { type: "text", step: step, min: min, max: max, value: displayValue, onChange: handleDirectInput, onBlur: handleBlurWithValidation, onFocus: handleFocus, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, className: `text-center bg-transparent text-lg font-semibold placeholder-gray-400 focus:outline-none border-none ${error ? 'text-red-700' : 'text-gray-900'} ${clearable && !isEmpty ? 'w-20 pr-6' : 'w-16'}`, style: {
694
- WebkitAppearance: 'none',
695
- MozAppearance: 'textfield',
696
- appearance: 'none',
697
- } }), clearable && !isEmpty && !disabled && (jsxRuntimeExports.jsx("button", { type: "button", onClick: handleClear, className: "absolute right-1 top-1/2 -translate-y-1/2 w-5 h-5 flex items-center justify-center rounded-full hover:bg-gray-200 active:bg-gray-300 transition-colors text-gray-500 hover:text-gray-700", title: "Clear value", "aria-label": "Clear", children: jsxRuntimeExports.jsx(g, { size: "sm", className: "w-3 h-3" }) }))] }), jsxRuntimeExports.jsx("button", { type: "button", onClick: handleIncrement, disabled: disabled || isAtMax, className: `flex-shrink-0 w-12 h-full flex items-center justify-center border-l border-gray-300 transition-all ${error
698
- ? 'text-red-500'
704
+ ? "opacity-40 cursor-not-allowed text-gray-400"
705
+ : "hover:bg-gray-100 active:bg-gray-200 text-gray-600"}`, title: "Decrease value", "aria-label": "Decrease", children: jsxRuntimeExports.jsx(R, { size: "md" }) }), jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center", children: jsxRuntimeExports.jsx("input", { type: "text", step: step, min: min, max: max, value: displayValue, onChange: handleDirectInput, onBlur: handleBlurWithValidation, onFocus: handleFocus, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, className: `text-center bg-transparent text-lg font-semibold placeholder-gray-400 focus:outline-none border-none ${error ? "text-red-700" : "text-gray-900"} w-full`, style: {
706
+ WebkitAppearance: "none",
707
+ MozAppearance: "textfield",
708
+ appearance: "none",
709
+ } }) }), clearable && !isEmpty && !disabled && (jsxRuntimeExports.jsx("button", { type: "button", onClick: handleClear, className: "flex-shrink-0 w-6 h-6 mr-2 flex items-center justify-center rounded-full transition-all hover:bg-gray-200 active:bg-gray-300 text-gray-500 hover:text-gray-700", title: "Clear value", "aria-label": "Clear", children: jsxRuntimeExports.jsx(g, { size: "sm" }) })), jsxRuntimeExports.jsx("button", { type: "button", onClick: handleIncrement, disabled: disabled || isAtMax, className: `flex-shrink-0 w-12 h-full flex items-center justify-center border-l border-gray-300 transition-all ${error
710
+ ? "text-red-500"
699
711
  : disabled || isAtMax
700
- ? 'opacity-40 cursor-not-allowed text-gray-400'
701
- : 'hover:bg-gray-100 active:bg-gray-200 text-gray-600'}`, title: "Increase value", "aria-label": "Increase", children: jsxRuntimeExports.jsx(U, { size: "md" }) })] }), error && (jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-start gap-1.5", children: [jsxRuntimeExports.jsx(m, { size: "sm", className: "text-red-500 flex-shrink-0 mt-0.5" }), jsxRuntimeExports.jsx("p", { className: "text-sm text-red-600 font-medium", children: error })] })), warning && !error && (jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-start gap-1.5", children: [jsxRuntimeExports.jsx("div", { className: "w-4 h-4 text-amber-500 flex-shrink-0 mt-0.5 flex items-center justify-center", children: jsxRuntimeExports.jsx("span", { className: "text-xs font-bold", children: "!" }) }), jsxRuntimeExports.jsx("p", { className: "text-sm text-amber-700", children: warning })] })), hint && !error && !warning && jsxRuntimeExports.jsx("p", { className: "mt-2 text-xs text-gray-500", children: hint })] }));
712
+ ? "opacity-40 cursor-not-allowed text-gray-400"
713
+ : "hover:bg-gray-100 active:bg-gray-200 text-gray-600"}`, title: "Increase value", "aria-label": "Increase", children: jsxRuntimeExports.jsx(U, { size: "md" }) })] }), error && (jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-start gap-1.5", children: [jsxRuntimeExports.jsx(m, { size: "sm", className: "text-red-500 flex-shrink-0 mt-0.5" }), jsxRuntimeExports.jsx("p", { className: "text-sm text-red-600 font-medium", children: error })] })), warning && !error && (jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-start gap-1.5", children: [jsxRuntimeExports.jsx("div", { className: "w-4 h-4 text-amber-500 flex-shrink-0 mt-0.5 flex items-center justify-center", children: jsxRuntimeExports.jsx("span", { className: "text-xs font-bold", children: "!" }) }), jsxRuntimeExports.jsx("p", { className: "text-sm text-amber-700", children: warning })] })), hint && !error && !warning && (jsxRuntimeExports.jsx("p", { className: "mt-2 text-xs text-gray-500", children: hint }))] }));
702
714
  }
703
715
 
704
716
  module.exports = NumericUpPicker;
package/dist/index.esm.js CHANGED
@@ -444,26 +444,33 @@ const hideSpinnersStyle = `
444
444
  -moz-appearance: textfield;
445
445
  }
446
446
  `;
447
- function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder, min, max, step = 0.01, error, hint, warning, disabled = false, className = '', required = false, useMinAsDefault = false, alwaysNegative = false, integerOnly = false, showSign = false, defaultToZero = false, clearable = false, onClear, }) {
447
+ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder, min, max, step = 0.01, error, hint, warning, disabled = false, className = "", required = false, useMinAsDefault = false, alwaysNegative = false, integerOnly = false, showSign = false, defaultToZero = false, clearable = false, onClear, }) {
448
448
  // Track if the field has been touched (user has focused on it)
449
449
  const [hasBeenTouched, setHasBeenTouched] = useState(false);
450
- const numValue = typeof value === 'string' ? parseFloat(value) || 0 : value;
450
+ const numValue = typeof value === "string" ? parseFloat(value) || 0 : value;
451
451
  // Format display value with sign if showSign is true
452
452
  const displayValue = useMemo(() => {
453
- if (!showSign || value === '' || value === '-' || value === null || value === undefined)
454
- return value || '';
453
+ if (!showSign ||
454
+ value === "" ||
455
+ value === "-" ||
456
+ value === null ||
457
+ value === undefined)
458
+ return value || "";
455
459
  const strValue = value.toString();
456
460
  const numVal = parseFloat(strValue);
457
461
  if (isNaN(numVal))
458
462
  return value;
459
- if (numVal > 0 && !strValue.startsWith('+')) {
463
+ if (numVal > 0 && !strValue.startsWith("+")) {
460
464
  return `+${strValue}`;
461
465
  }
462
466
  return value;
463
467
  }, [value, showSign]);
464
468
  const handleIncrement = () => {
465
469
  // If value is empty or invalid, start from 0 if defaultToZero, otherwise from min (or 0 if no min)
466
- if (value === '' || value === '-' || value === null || value === undefined) {
470
+ if (value === "" ||
471
+ value === "-" ||
472
+ value === null ||
473
+ value === undefined) {
467
474
  const startValue = defaultToZero ? 0 : min !== undefined ? min : 0;
468
475
  if (integerOnly) {
469
476
  onChange(Math.round(startValue).toString());
@@ -481,13 +488,18 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
481
488
  else {
482
489
  const formattedValue = newValue.toFixed(2);
483
490
  // If alwaysNegative, ensure the value has a negative sign
484
- onChange(alwaysNegative && newValue > 0 ? `-${formattedValue}` : formattedValue);
491
+ onChange(alwaysNegative && newValue > 0
492
+ ? `-${formattedValue}`
493
+ : formattedValue);
485
494
  }
486
495
  }
487
496
  };
488
497
  const handleDecrement = () => {
489
498
  // If value is empty or invalid, start from 0 if defaultToZero, otherwise from max (or 0 if no max)
490
- if (value === '' || value === '-' || value === null || value === undefined) {
499
+ if (value === "" ||
500
+ value === "-" ||
501
+ value === null ||
502
+ value === undefined) {
491
503
  const startValue = defaultToZero ? 0 : max !== undefined ? max : 0;
492
504
  if (integerOnly) {
493
505
  onChange(Math.round(startValue).toString());
@@ -514,11 +526,11 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
514
526
  };
515
527
  const handleKeyDown = (e) => {
516
528
  // Handle arrow up/down keys for incrementing/decrementing
517
- if (e.key === 'ArrowUp') {
529
+ if (e.key === "ArrowUp") {
518
530
  e.preventDefault(); // Prevent cursor movement
519
531
  handleIncrement();
520
532
  }
521
- else if (e.key === 'ArrowDown') {
533
+ else if (e.key === "ArrowDown") {
522
534
  e.preventDefault(); // Prevent cursor movement
523
535
  handleDecrement();
524
536
  }
@@ -534,22 +546,22 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
534
546
  let inputValue = e.target.value;
535
547
  // For showSign, remove the plus sign before processing
536
548
  if (showSign) {
537
- inputValue = inputValue.replace(/^\+/, '');
549
+ inputValue = inputValue.replace(/^\+/, "");
538
550
  }
539
551
  // For alwaysNegative fields, ensure value always starts with minus sign
540
552
  if (alwaysNegative) {
541
553
  // Remove any existing minus signs
542
- inputValue = inputValue.replace(/-/g, '');
554
+ inputValue = inputValue.replace(/-/g, "");
543
555
  // Allow empty input
544
- if (inputValue === '') {
545
- onChange('-');
556
+ if (inputValue === "") {
557
+ onChange("-");
546
558
  return;
547
559
  }
548
560
  // Add minus sign at the beginning
549
561
  inputValue = `-${inputValue}`;
550
562
  }
551
563
  // Allow empty input (user deleted content)
552
- if (inputValue === '' || inputValue === '-') {
564
+ if (inputValue === "" || inputValue === "-") {
553
565
  onChange(inputValue);
554
566
  return;
555
567
  }
@@ -557,16 +569,16 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
557
569
  onChange(inputValue);
558
570
  };
559
571
  const handleClear = () => {
560
- onChange('');
572
+ onChange("");
561
573
  onClear?.();
562
574
  };
563
575
  const handleBlurWithValidation = () => {
564
576
  const inputValue = value.toString();
565
577
  // If empty, handle based on required and useMinAsDefault flags
566
- if (inputValue === '' || inputValue === '-') {
578
+ if (inputValue === "" || inputValue === "-") {
567
579
  // For optional fields (!required), allow empty values
568
580
  if (!required) {
569
- onChange('');
581
+ onChange("");
570
582
  onBlur?.();
571
583
  return;
572
584
  }
@@ -592,17 +604,17 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
592
604
  }
593
605
  else if (!hasBeenTouched) {
594
606
  // If never touched, keep it empty
595
- onChange('');
607
+ onChange("");
596
608
  }
597
609
  else {
598
- onChange(integerOnly ? '0' : alwaysNegative ? '-0.00' : '0.00');
610
+ onChange(integerOnly ? "0" : alwaysNegative ? "-0.00" : "0.00");
599
611
  }
600
612
  onBlur?.();
601
613
  return;
602
614
  }
603
615
  // Parse the input value (remove negative sign if present for alwaysNegative fields)
604
616
  let numericValue = alwaysNegative
605
- ? parseFloat(inputValue.replace(/^-/, ''))
617
+ ? parseFloat(inputValue.replace(/^-/, ""))
606
618
  : parseFloat(inputValue);
607
619
  // If not a valid number, reset to min or 0
608
620
  if (isNaN(numericValue)) {
@@ -625,7 +637,7 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
625
637
  }
626
638
  }
627
639
  else {
628
- onChange(integerOnly ? '0' : alwaysNegative ? '-0.00' : '0.00');
640
+ onChange(integerOnly ? "0" : alwaysNegative ? "-0.00" : "0.00");
629
641
  }
630
642
  onBlur?.();
631
643
  return;
@@ -670,7 +682,7 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
670
682
  };
671
683
  // Disable buttons only if value is not empty and at min/max
672
684
  // When value is empty, allow both buttons (they will set to min/max)
673
- const isEmpty = value === '' || value === '-' || value === null || value === undefined;
685
+ const isEmpty = value === "" || value === "-" || value === null || value === undefined;
674
686
  // For alwaysNegative fields, we compare absolute values
675
687
  const isAtMin = !isEmpty &&
676
688
  (alwaysNegative
@@ -680,23 +692,23 @@ function NumericUpPicker({ label, value, onChange, onBlur, onFocus, placeholder,
680
692
  (alwaysNegative
681
693
  ? max !== undefined && Math.abs(numValue) <= Math.abs(max)
682
694
  : max !== undefined && numValue >= max);
683
- return (jsxRuntimeExports.jsxs("div", { className: className, children: [jsxRuntimeExports.jsx("style", { children: hideSpinnersStyle }), label && (jsxRuntimeExports.jsxs("label", { className: `block text-sm font-medium mb-2 ${error ? 'text-red-700' : 'text-gray-700'}`, children: [label, required && jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })] })), jsxRuntimeExports.jsxs("div", { className: `flex items-center justify-between h-12 rounded-lg border-2 transition-all ${error
684
- ? 'border-red-500 bg-red-50'
695
+ return (jsxRuntimeExports.jsxs("div", { className: className, children: [jsxRuntimeExports.jsx("style", { children: hideSpinnersStyle }), label && (jsxRuntimeExports.jsxs("label", { className: `block text-sm font-medium mb-2 ${error ? "text-red-700" : "text-gray-700"}`, children: [label, required && jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })] })), jsxRuntimeExports.jsxs("div", { className: `flex items-center justify-between h-12 rounded-lg border-2 transition-all ${error
696
+ ? "border-red-500 bg-red-50"
685
697
  : disabled
686
- ? 'border-gray-300 bg-gray-100 opacity-50 cursor-not-allowed'
687
- : 'border-gray-300 bg-gray-50'}`, children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: handleDecrement, disabled: disabled || isAtMin, className: `flex-shrink-0 w-12 h-full flex items-center justify-center border-r border-gray-300 transition-all ${error
688
- ? 'text-red-500'
698
+ ? "border-gray-300 bg-gray-100 opacity-50 cursor-not-allowed"
699
+ : "border-gray-300 bg-gray-50"}`, children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: handleDecrement, disabled: disabled || isAtMin, className: `flex-shrink-0 w-12 h-full flex items-center justify-center border-r border-gray-300 transition-all ${error
700
+ ? "text-red-500"
689
701
  : disabled || isAtMin
690
- ? 'opacity-40 cursor-not-allowed text-gray-400'
691
- : 'hover:bg-gray-100 active:bg-gray-200 text-gray-600'}`, title: "Decrease value", "aria-label": "Decrease", children: jsxRuntimeExports.jsx(R, { size: "md" }) }), jsxRuntimeExports.jsxs("div", { className: "flex-1 flex items-center justify-center relative", children: [jsxRuntimeExports.jsx("input", { type: "text", step: step, min: min, max: max, value: displayValue, onChange: handleDirectInput, onBlur: handleBlurWithValidation, onFocus: handleFocus, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, className: `text-center bg-transparent text-lg font-semibold placeholder-gray-400 focus:outline-none border-none ${error ? 'text-red-700' : 'text-gray-900'} ${clearable && !isEmpty ? 'w-20 pr-6' : 'w-16'}`, style: {
692
- WebkitAppearance: 'none',
693
- MozAppearance: 'textfield',
694
- appearance: 'none',
695
- } }), clearable && !isEmpty && !disabled && (jsxRuntimeExports.jsx("button", { type: "button", onClick: handleClear, className: "absolute right-1 top-1/2 -translate-y-1/2 w-5 h-5 flex items-center justify-center rounded-full hover:bg-gray-200 active:bg-gray-300 transition-colors text-gray-500 hover:text-gray-700", title: "Clear value", "aria-label": "Clear", children: jsxRuntimeExports.jsx(g, { size: "sm", className: "w-3 h-3" }) }))] }), jsxRuntimeExports.jsx("button", { type: "button", onClick: handleIncrement, disabled: disabled || isAtMax, className: `flex-shrink-0 w-12 h-full flex items-center justify-center border-l border-gray-300 transition-all ${error
696
- ? 'text-red-500'
702
+ ? "opacity-40 cursor-not-allowed text-gray-400"
703
+ : "hover:bg-gray-100 active:bg-gray-200 text-gray-600"}`, title: "Decrease value", "aria-label": "Decrease", children: jsxRuntimeExports.jsx(R, { size: "md" }) }), jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center", children: jsxRuntimeExports.jsx("input", { type: "text", step: step, min: min, max: max, value: displayValue, onChange: handleDirectInput, onBlur: handleBlurWithValidation, onFocus: handleFocus, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, className: `text-center bg-transparent text-lg font-semibold placeholder-gray-400 focus:outline-none border-none ${error ? "text-red-700" : "text-gray-900"} w-full`, style: {
704
+ WebkitAppearance: "none",
705
+ MozAppearance: "textfield",
706
+ appearance: "none",
707
+ } }) }), clearable && !isEmpty && !disabled && (jsxRuntimeExports.jsx("button", { type: "button", onClick: handleClear, className: "flex-shrink-0 w-6 h-6 mr-2 flex items-center justify-center rounded-full transition-all hover:bg-gray-200 active:bg-gray-300 text-gray-500 hover:text-gray-700", title: "Clear value", "aria-label": "Clear", children: jsxRuntimeExports.jsx(g, { size: "sm" }) })), jsxRuntimeExports.jsx("button", { type: "button", onClick: handleIncrement, disabled: disabled || isAtMax, className: `flex-shrink-0 w-12 h-full flex items-center justify-center border-l border-gray-300 transition-all ${error
708
+ ? "text-red-500"
697
709
  : disabled || isAtMax
698
- ? 'opacity-40 cursor-not-allowed text-gray-400'
699
- : 'hover:bg-gray-100 active:bg-gray-200 text-gray-600'}`, title: "Increase value", "aria-label": "Increase", children: jsxRuntimeExports.jsx(U, { size: "md" }) })] }), error && (jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-start gap-1.5", children: [jsxRuntimeExports.jsx(m, { size: "sm", className: "text-red-500 flex-shrink-0 mt-0.5" }), jsxRuntimeExports.jsx("p", { className: "text-sm text-red-600 font-medium", children: error })] })), warning && !error && (jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-start gap-1.5", children: [jsxRuntimeExports.jsx("div", { className: "w-4 h-4 text-amber-500 flex-shrink-0 mt-0.5 flex items-center justify-center", children: jsxRuntimeExports.jsx("span", { className: "text-xs font-bold", children: "!" }) }), jsxRuntimeExports.jsx("p", { className: "text-sm text-amber-700", children: warning })] })), hint && !error && !warning && jsxRuntimeExports.jsx("p", { className: "mt-2 text-xs text-gray-500", children: hint })] }));
710
+ ? "opacity-40 cursor-not-allowed text-gray-400"
711
+ : "hover:bg-gray-100 active:bg-gray-200 text-gray-600"}`, title: "Increase value", "aria-label": "Increase", children: jsxRuntimeExports.jsx(U, { size: "md" }) })] }), error && (jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-start gap-1.5", children: [jsxRuntimeExports.jsx(m, { size: "sm", className: "text-red-500 flex-shrink-0 mt-0.5" }), jsxRuntimeExports.jsx("p", { className: "text-sm text-red-600 font-medium", children: error })] })), warning && !error && (jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-start gap-1.5", children: [jsxRuntimeExports.jsx("div", { className: "w-4 h-4 text-amber-500 flex-shrink-0 mt-0.5 flex items-center justify-center", children: jsxRuntimeExports.jsx("span", { className: "text-xs font-bold", children: "!" }) }), jsxRuntimeExports.jsx("p", { className: "text-sm text-amber-700", children: warning })] })), hint && !error && !warning && (jsxRuntimeExports.jsx("p", { className: "mt-2 text-xs text-gray-500", children: hint }))] }));
700
712
  }
701
713
 
702
714
  export { NumericUpPicker as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubenpazch/numeric-up-picker",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "repository": "https://github.com/rubenpazch/lbyte-ui-library.git",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -24,10 +24,10 @@
24
24
  "react-dom": "^19.0.0"
25
25
  },
26
26
  "dependencies": {
27
- "@rubenpazch/icons": "2.0.0"
27
+ "@rubenpazch/icons": "3.0.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@rubenpazch/typescript-config": "2.0.0"
30
+ "@rubenpazch/typescript-config": "3.0.0"
31
31
  },
32
32
  "scripts": {
33
33
  "build": "rollup -c",