jattac.libs.web.zest-button 1.1.0 → 1.1.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/dist/index.cjs.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var require$$0 = require('react');
4
- var fa = require('react-icons/fa');
4
+ var fa6 = require('react-icons/fa6');
5
5
 
6
6
  var jsxRuntime = {exports: {}};
7
7
 
@@ -1396,10 +1396,22 @@ const ZestButton = ({ visualOptions = {}, busyOptions = {}, successOptions = {},
1396
1396
  const { variant = "standard", size = "md", fullWidth = false, iconLeft, iconRight, } = visualOptions;
1397
1397
  const { handleInternally = true, preventRageClick = true, minBusyDurationMs = 500, } = busyOptions;
1398
1398
  const { showCheckmark = true, showFailIcon = true, autoResetAfterMs = 2000, } = successOptions;
1399
+ // Edge Case 4: Add warnings for very short durations in development
1400
+ require$$0.useEffect(() => {
1401
+ if (process.env.NODE_ENV === 'development') {
1402
+ if (minBusyDurationMs > 0 && minBusyDurationMs < 100) {
1403
+ console.warn(`ZestButton: 'minBusyDurationMs' is set to ${minBusyDurationMs}ms. Very short durations can lead to visual flickering and a poor user experience. Consider a value of 100ms or more.`);
1404
+ }
1405
+ if (autoResetAfterMs > 0 && autoResetAfterMs < 100) {
1406
+ console.warn(`ZestButton: 'autoResetAfterMs' is set to ${autoResetAfterMs}ms. Very short durations can make success/fail feedback hard to perceive. Consider a value of 100ms or more.`);
1407
+ }
1408
+ }
1409
+ }, [minBusyDurationMs, autoResetAfterMs]);
1399
1410
  const [internalBusy, setInternalBusy] = require$$0.useState(false);
1400
1411
  const [wasSuccessful, setWasSuccessful] = require$$0.useState(false);
1401
1412
  const [wasFailed, setWasFailed] = require$$0.useState(false);
1402
1413
  const buttonRef = require$$0.useRef(null);
1414
+ const failTimeoutRef = require$$0.useRef(null); // Bug 1: Add useRef for failTimeout
1403
1415
  const [currentChildren, setCurrentChildren] = require$$0.useState(children);
1404
1416
  const [awaitingConfirm, setAwaitingConfirm] = require$$0.useState(false);
1405
1417
  // ✅ interval ref for confirm countdown
@@ -1418,6 +1430,15 @@ const ZestButton = ({ visualOptions = {}, busyOptions = {}, successOptions = {},
1418
1430
  const isDisabled = disabled ||
1419
1431
  effectiveBusy ||
1420
1432
  (preventRageClick && (wasSuccessful || wasFailed));
1433
+ // Move handleClick, stopWaiting, and handleConfirmClick declarations here
1434
+ const stopWaiting = () => {
1435
+ if (confirmIntervalRef.current) {
1436
+ clearInterval(confirmIntervalRef.current);
1437
+ confirmIntervalRef.current = null;
1438
+ }
1439
+ setCurrentChildren(children);
1440
+ setAwaitingConfirm(false);
1441
+ };
1421
1442
  const handleClick = async (e) => {
1422
1443
  if (preventRageClick && internalBusy)
1423
1444
  return;
@@ -1449,45 +1470,14 @@ const ZestButton = ({ visualOptions = {}, busyOptions = {}, successOptions = {},
1449
1470
  onClick(e);
1450
1471
  }
1451
1472
  };
1452
- // auto-reset success/failure state
1453
- require$$0.useEffect(() => {
1454
- if ((wasSuccessful || wasFailed) && autoResetAfterMs) {
1455
- const timeout = setTimeout(() => {
1456
- setWasSuccessful(false);
1457
- setWasFailed(false);
1458
- }, autoResetAfterMs);
1459
- return () => clearTimeout(timeout);
1460
- }
1461
- }, [wasSuccessful, wasFailed, autoResetAfterMs]);
1462
- // Enter key handler if isDefault
1463
- require$$0.useEffect(() => {
1464
- if (!isDefault || isDisabled)
1465
- return;
1466
- const listener = (e) => {
1467
- const target = e.target;
1468
- if (e.key === "Enter" &&
1469
- !e.repeat &&
1470
- !e.defaultPrevented &&
1471
- !(target instanceof HTMLTextAreaElement)) {
1472
- e.preventDefault();
1473
- buttonRef.current?.click();
1474
- }
1475
- };
1476
- document.addEventListener("keydown", listener);
1477
- return () => document.removeEventListener("keydown", listener);
1478
- }, [isDefault, isDisabled]);
1479
- const stopWaiting = () => {
1480
- if (confirmIntervalRef.current) {
1481
- clearInterval(confirmIntervalRef.current);
1482
- confirmIntervalRef.current = null;
1483
- }
1484
- setCurrentChildren(children);
1485
- setAwaitingConfirm(false);
1486
- };
1487
1473
  const handleConfirmClick = async (e) => {
1488
1474
  if (!props.confirmOptions) {
1489
1475
  return handleClick(e);
1490
1476
  }
1477
+ // Edge Case 3: Add warning for missing onClick with confirmOptions
1478
+ if (props.confirmOptions && !onClick) { // Use destructured onClick
1479
+ console.warn("ZestButton: 'confirmOptions' are provided but 'onClick' handler is missing. The button will confirm but perform no action.");
1480
+ }
1491
1481
  if (awaitingConfirm) {
1492
1482
  stopWaiting();
1493
1483
  return handleClick(e);
@@ -1502,33 +1492,69 @@ const ZestButton = ({ visualOptions = {}, busyOptions = {}, successOptions = {},
1502
1492
  if (timeRemaining <= 0) {
1503
1493
  stopWaiting();
1504
1494
  setWasFailed(true); // Indicate failure for shake animation
1505
- setTimeout(() => {
1495
+ // Bug 1: Clear any existing timeout before setting a new one
1496
+ if (failTimeoutRef.current) {
1497
+ clearTimeout(failTimeoutRef.current);
1498
+ }
1499
+ failTimeoutRef.current = setTimeout(() => {
1506
1500
  setWasFailed(false);
1501
+ failTimeoutRef.current = null; // Clear ref after timeout fires
1507
1502
  }, 400); // Shake animation duration
1508
- // No need to return clearTimeout, as this timeout is for visual feedback only
1509
1503
  }
1510
1504
  else {
1511
1505
  setCurrentChildren(`${displayLabel} (${timeRemaining}s)`);
1512
1506
  }
1513
1507
  }, 1000); // Update once per second
1514
1508
  };
1509
+ // auto-reset success/failure state
1510
+ require$$0.useEffect(() => {
1511
+ if ((wasSuccessful || wasFailed) && autoResetAfterMs) {
1512
+ const timeout = setTimeout(() => {
1513
+ setWasSuccessful(false);
1514
+ setWasFailed(false);
1515
+ }, autoResetAfterMs);
1516
+ return () => clearTimeout(timeout);
1517
+ }
1518
+ }, [wasSuccessful, wasFailed, autoResetAfterMs]);
1519
+ // Enter key handler if isDefault
1520
+ require$$0.useEffect(() => {
1521
+ if (!isDefault || isDisabled)
1522
+ return;
1523
+ const listener = (e) => {
1524
+ const target = e.target;
1525
+ if (e.key === "Enter" &&
1526
+ !e.repeat &&
1527
+ !e.defaultPrevented &&
1528
+ !(target instanceof HTMLTextAreaElement)) {
1529
+ e.preventDefault();
1530
+ // Bug 2: Directly call handleConfirmClick to respect confirmation logic
1531
+ handleConfirmClick(e);
1532
+ }
1533
+ };
1534
+ document.addEventListener("keydown", listener);
1535
+ return () => document.removeEventListener("keydown", listener);
1536
+ }, [isDefault, isDisabled, handleConfirmClick]); // Bug 2: Add handleConfirmClick to dependencies
1515
1537
  // cleanup on unmount
1516
1538
  require$$0.useEffect(() => {
1517
1539
  return () => {
1518
1540
  if (confirmIntervalRef.current) {
1519
1541
  clearInterval(confirmIntervalRef.current);
1520
1542
  }
1543
+ // Bug 1: Add cleanup for failTimeoutRef
1544
+ if (failTimeoutRef.current) {
1545
+ clearTimeout(failTimeoutRef.current);
1546
+ }
1521
1547
  };
1522
1548
  }, []);
1523
1549
  const renderLeftIcon = () => {
1524
1550
  if (effectiveBusy) {
1525
- return (jsxRuntimeExports.jsx("span", { className: `${styles.icon} ${styles.fadeIn}`, children: jsxRuntimeExports.jsx(fa.FaSpinner, { className: styles.spinner }) }));
1551
+ return (jsxRuntimeExports.jsx("span", { className: `${styles.icon} ${styles.fadeIn}`, children: jsxRuntimeExports.jsx(fa6.FaSpinner, { className: styles.spinner }) }));
1526
1552
  }
1527
1553
  else if (wasSuccessful && showCheckmark) {
1528
1554
  return (jsxRuntimeExports.jsx("span", { className: `${styles.icon} ${styles.fadeIn}`, children: jsxRuntimeExports.jsx(AnimatedCheckmark, {}) }));
1529
1555
  }
1530
1556
  else if (wasFailed && showFailIcon) {
1531
- return (jsxRuntimeExports.jsx("span", { className: `${styles.icon} ${styles.fadeIn} ${styles.shake}`, children: jsxRuntimeExports.jsx(AnimatedX, {}) }));
1557
+ return (jsxRuntimeExports.jsx("span", { className: `${styles.icon} ${styles.fadeIn}`, children: jsxRuntimeExports.jsx(AnimatedX, {}) }));
1532
1558
  }
1533
1559
  else if (iconLeft) {
1534
1560
  return jsxRuntimeExports.jsx("span", { className: styles.icon, children: iconLeft });