jattac.libs.web.zest-button 1.2.2 → 1.2.3
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 +7 -5
- package/dist/ZestButton.d.ts +6 -2
- package/dist/ZestContext.d.ts +9 -0
- package/dist/ZestProvider.d.ts +8 -0
- package/dist/hooks/useBusyState.d.ts +20 -0
- package/dist/hooks/useConfirmation.d.ts +13 -0
- package/dist/hooks/useThemeDetection.d.ts +1 -0
- package/dist/hooks/useZestConfig.d.ts +2 -0
- package/dist/index.cjs.js +376 -110
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +18 -2
- package/dist/index.esm.js +375 -111
- package/dist/index.esm.js.map +1 -1
- package/dist/semanticTypeDefaults.d.ts +4 -0
- package/docs/api.md +119 -0
- package/docs/breaking-changes.md +52 -0
- package/docs/configuration.md +192 -0
- package/docs/development.md +77 -0
- package/docs/examples.md +215 -0
- package/docs/features.md +113 -0
- package/package.json +24 -7
package/dist/index.cjs.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var require$$0 = require('react');
|
|
4
4
|
var fa6 = require('react-icons/fa6');
|
|
5
|
+
var fa = require('react-icons/fa');
|
|
5
6
|
|
|
6
7
|
var jsxRuntime = {exports: {}};
|
|
7
8
|
|
|
@@ -1389,18 +1390,218 @@ var css_248z = "/* Styles/ZestButton.module.css */\n\n/* Define base variables f
|
|
|
1389
1390
|
var styles = {"force-light":"ZestButton-module_force-light__zZTIZ","force-dark":"ZestButton-module_force-dark__cx74D","button":"ZestButton-module_button__KDafc","solid":"ZestButton-module_solid__cu4tr","outline":"ZestButton-module_outline__esgLq","text":"ZestButton-module_text__8X1xD","dashed":"ZestButton-module_dashed__ebKYF","standard":"ZestButton-module_standard__T3EGM","success":"ZestButton-module_success__XEptA","danger":"ZestButton-module_danger__nJpJ-","disabled":"ZestButton-module_disabled__gw6y3","fullWidth":"ZestButton-module_fullWidth__2ziwk","sm":"ZestButton-module_sm__G1vAP","md":"ZestButton-module_md__Y-PMO","lg":"ZestButton-module_lg__AQgdf","inner":"ZestButton-module_inner__1j2Fr","spinner":"ZestButton-module_spinner__l2hLe","spin":"ZestButton-module_spin__4asdw","content":"ZestButton-module_content__hlea3","label":"ZestButton-module_label__8x263","icon":"ZestButton-module_icon__B3DFi","animatedCheck":"ZestButton-module_animatedCheck__8K4K-","fadeIn":"ZestButton-module_fadeIn__iEave","animatedX":"ZestButton-module_animatedX__KQnt7","drawCheck":"ZestButton-module_drawCheck__3DyjT","shake":"ZestButton-module_shake__NtIjf","shakeIt":"ZestButton-module_shakeIt__ox-R3"};
|
|
1390
1391
|
styleInject(css_248z);
|
|
1391
1392
|
|
|
1392
|
-
//
|
|
1393
|
-
const
|
|
1394
|
-
|
|
1395
|
-
const
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
//
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1393
|
+
// Create the Zest Context with a default empty configuration
|
|
1394
|
+
const ZestContext = require$$0.createContext(undefined);
|
|
1395
|
+
// Custom hook to use the Zest Context
|
|
1396
|
+
const useZest = () => {
|
|
1397
|
+
const context = require$$0.useContext(ZestContext);
|
|
1398
|
+
// Optional: Add a check here if context is undefined, meaning provider is not used
|
|
1399
|
+
// if (context === undefined) {
|
|
1400
|
+
// console.warn("useZest must be used within a ZestProvider. Falling back to default ZestButton props.");
|
|
1401
|
+
// }
|
|
1402
|
+
return context;
|
|
1403
|
+
};
|
|
1404
|
+
|
|
1405
|
+
const semanticTypeDefaults = {
|
|
1406
|
+
// Creation / Add
|
|
1407
|
+
'add': {
|
|
1408
|
+
visualOptions: {
|
|
1409
|
+
variant: 'standard',
|
|
1410
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaPlus, {}),
|
|
1411
|
+
},
|
|
1412
|
+
},
|
|
1413
|
+
'new': {
|
|
1414
|
+
visualOptions: {
|
|
1415
|
+
variant: 'standard',
|
|
1416
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaPlus, {}),
|
|
1417
|
+
},
|
|
1418
|
+
},
|
|
1419
|
+
// Save / Submit
|
|
1420
|
+
'save': {
|
|
1421
|
+
visualOptions: {
|
|
1422
|
+
variant: 'success',
|
|
1423
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaSave, {}),
|
|
1424
|
+
},
|
|
1425
|
+
busyOptions: { minBusyDurationMs: 500 }, // Default busy duration for saves
|
|
1426
|
+
successOptions: { showCheckmark: true },
|
|
1427
|
+
},
|
|
1428
|
+
'submit': {
|
|
1429
|
+
visualOptions: {
|
|
1430
|
+
variant: 'success',
|
|
1431
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaSave, {}),
|
|
1432
|
+
},
|
|
1433
|
+
busyOptions: { minBusyDurationMs: 500 },
|
|
1434
|
+
successOptions: { showCheckmark: true },
|
|
1435
|
+
},
|
|
1436
|
+
// Edit / Update
|
|
1437
|
+
'edit': {
|
|
1438
|
+
visualOptions: {
|
|
1439
|
+
variant: 'standard',
|
|
1440
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaEdit, {}),
|
|
1441
|
+
},
|
|
1442
|
+
},
|
|
1443
|
+
'update': {
|
|
1444
|
+
visualOptions: {
|
|
1445
|
+
variant: 'standard',
|
|
1446
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaEdit, {}),
|
|
1447
|
+
},
|
|
1448
|
+
},
|
|
1449
|
+
// Delete / Remove
|
|
1450
|
+
'delete': {
|
|
1451
|
+
visualOptions: {
|
|
1452
|
+
variant: 'danger',
|
|
1453
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaTrash, {}),
|
|
1454
|
+
},
|
|
1455
|
+
confirmOptions: {
|
|
1456
|
+
displayLabel: 'Confirm Delete',
|
|
1457
|
+
timeoutSecs: 5,
|
|
1458
|
+
},
|
|
1459
|
+
successOptions: { showFailIcon: true, autoResetAfterMs: 400 }, // Shake for fail
|
|
1460
|
+
},
|
|
1461
|
+
'remove': {
|
|
1462
|
+
visualOptions: {
|
|
1463
|
+
variant: 'danger',
|
|
1464
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaTrash, {}),
|
|
1465
|
+
},
|
|
1466
|
+
confirmOptions: {
|
|
1467
|
+
displayLabel: 'Confirm Remove',
|
|
1468
|
+
timeoutSecs: 5,
|
|
1469
|
+
},
|
|
1470
|
+
successOptions: { showFailIcon: true, autoResetAfterMs: 400 },
|
|
1471
|
+
},
|
|
1472
|
+
// Cancel / Close
|
|
1473
|
+
'cancel': {
|
|
1474
|
+
buttonStyle: 'outline', // Moved here
|
|
1475
|
+
visualOptions: {
|
|
1476
|
+
variant: 'standard',
|
|
1477
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaTimes, {}),
|
|
1478
|
+
},
|
|
1479
|
+
},
|
|
1480
|
+
'close': {
|
|
1481
|
+
buttonStyle: 'outline', // Moved here
|
|
1482
|
+
visualOptions: {
|
|
1483
|
+
variant: 'standard',
|
|
1484
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaTimes, {}),
|
|
1485
|
+
},
|
|
1486
|
+
},
|
|
1487
|
+
// View / Details
|
|
1488
|
+
'view': {
|
|
1489
|
+
buttonStyle: 'text', // Moved here
|
|
1490
|
+
visualOptions: {
|
|
1491
|
+
variant: 'standard',
|
|
1492
|
+
iconRight: jsxRuntimeExports.jsx(fa.FaArrowRight, {}),
|
|
1493
|
+
},
|
|
1494
|
+
},
|
|
1495
|
+
'details': {
|
|
1496
|
+
buttonStyle: 'text', // Moved here
|
|
1497
|
+
visualOptions: {
|
|
1498
|
+
variant: 'standard',
|
|
1499
|
+
iconRight: jsxRuntimeExports.jsx(fa.FaArrowRight, {}),
|
|
1500
|
+
},
|
|
1501
|
+
},
|
|
1502
|
+
// Download
|
|
1503
|
+
'download': {
|
|
1504
|
+
visualOptions: {
|
|
1505
|
+
variant: 'standard',
|
|
1506
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaDownload, {}),
|
|
1507
|
+
},
|
|
1508
|
+
},
|
|
1509
|
+
// Upload
|
|
1510
|
+
'upload': {
|
|
1511
|
+
visualOptions: {
|
|
1512
|
+
variant: 'standard',
|
|
1513
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaUpload, {}),
|
|
1514
|
+
},
|
|
1515
|
+
},
|
|
1516
|
+
// Refresh / Reload
|
|
1517
|
+
'refresh': {
|
|
1518
|
+
visualOptions: {
|
|
1519
|
+
variant: 'standard',
|
|
1520
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaSyncAlt, {}),
|
|
1521
|
+
},
|
|
1522
|
+
busyOptions: { minBusyDurationMs: 500 },
|
|
1523
|
+
},
|
|
1524
|
+
'reload': {
|
|
1525
|
+
visualOptions: {
|
|
1526
|
+
variant: 'standard',
|
|
1527
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaSyncAlt, {}),
|
|
1528
|
+
},
|
|
1529
|
+
busyOptions: { minBusyDurationMs: 500 },
|
|
1530
|
+
},
|
|
1531
|
+
// Print
|
|
1532
|
+
'print': {
|
|
1533
|
+
visualOptions: {
|
|
1534
|
+
variant: 'standard',
|
|
1535
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaPrint, {}),
|
|
1536
|
+
},
|
|
1537
|
+
},
|
|
1538
|
+
// Share
|
|
1539
|
+
'share': {
|
|
1540
|
+
visualOptions: {
|
|
1541
|
+
variant: 'standard',
|
|
1542
|
+
iconLeft: jsxRuntimeExports.jsx(fa.FaShareAlt, {}),
|
|
1543
|
+
},
|
|
1544
|
+
},
|
|
1545
|
+
// Confirm (generic)
|
|
1546
|
+
'confirm': {
|
|
1547
|
+
visualOptions: {
|
|
1548
|
+
variant: 'success', // Could be standard or success
|
|
1549
|
+
},
|
|
1550
|
+
confirmOptions: {
|
|
1551
|
+
displayLabel: 'Are you sure?',
|
|
1552
|
+
timeoutSecs: 5,
|
|
1553
|
+
},
|
|
1554
|
+
},
|
|
1555
|
+
};
|
|
1556
|
+
|
|
1557
|
+
// Define a deep merge utility function
|
|
1558
|
+
const deepMerge = (target, source) => {
|
|
1559
|
+
const output = { ...target };
|
|
1560
|
+
if (target && typeof target === 'object' && source && typeof source === 'object') {
|
|
1561
|
+
Object.keys(source).forEach(key => {
|
|
1562
|
+
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
1563
|
+
if (!(key in target))
|
|
1564
|
+
Object.assign(output, { [key]: source[key] });
|
|
1565
|
+
else
|
|
1566
|
+
output[key] = deepMerge(target[key], source[key]);
|
|
1567
|
+
}
|
|
1568
|
+
else {
|
|
1569
|
+
Object.assign(output, { [key]: source[key] });
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
return output;
|
|
1574
|
+
};
|
|
1575
|
+
const useZestConfig = (localZestProps) => {
|
|
1576
|
+
const globalConfig = useZest();
|
|
1577
|
+
const globalDefaultProps = globalConfig?.defaultProps;
|
|
1578
|
+
const customSemanticDefaults = globalConfig?.semanticTypeDefaults;
|
|
1579
|
+
// 1. Start with global defaults (lowest precedence)
|
|
1580
|
+
let effectiveZestConfig = deepMerge({}, globalDefaultProps || {});
|
|
1581
|
+
// Determine the semanticType from either local props or the already-merged global props
|
|
1582
|
+
const semanticType = localZestProps?.semanticType || effectiveZestConfig.semanticType;
|
|
1583
|
+
if (semanticType) {
|
|
1584
|
+
// 2. Apply built-in semantic defaults
|
|
1585
|
+
if (semanticTypeDefaults[semanticType]) {
|
|
1586
|
+
effectiveZestConfig = deepMerge(effectiveZestConfig, semanticTypeDefaults[semanticType]);
|
|
1587
|
+
}
|
|
1588
|
+
// 3. Apply custom semantic defaults from provider (overrides built-in ones)
|
|
1589
|
+
if (customSemanticDefaults && customSemanticDefaults[semanticType]) {
|
|
1590
|
+
effectiveZestConfig = deepMerge(effectiveZestConfig, customSemanticDefaults[semanticType]);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
// 4. Apply local props (highest precedence)
|
|
1594
|
+
effectiveZestConfig = deepMerge(effectiveZestConfig, localZestProps || {});
|
|
1595
|
+
return effectiveZestConfig;
|
|
1596
|
+
};
|
|
1597
|
+
|
|
1598
|
+
const useBusyState = ({ busyOptions, successOptions }) => {
|
|
1599
|
+
const [internalBusy, setInternalBusy] = require$$0.useState(false);
|
|
1600
|
+
const [wasSuccessful, setWasSuccessful] = require$$0.useState(false);
|
|
1601
|
+
const [wasFailed, setWasFailed] = require$$0.useState(false);
|
|
1602
|
+
const failTimeoutRef = require$$0.useRef(null);
|
|
1603
|
+
const { handleInternally = true, preventRageClick = true, minBusyDurationMs = 500, } = busyOptions || {};
|
|
1604
|
+
const { showCheckmark = true, showFailIcon = true, autoResetAfterMs = 2000, } = successOptions || {};
|
|
1404
1605
|
// Edge Case 4: Add warnings for very short durations in development
|
|
1405
1606
|
require$$0.useEffect(() => {
|
|
1406
1607
|
if (process.env.NODE_ENV === 'development') {
|
|
@@ -1412,16 +1613,120 @@ zest, // New parent prop
|
|
|
1412
1613
|
}
|
|
1413
1614
|
}
|
|
1414
1615
|
}, [minBusyDurationMs, autoResetAfterMs]);
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1616
|
+
// auto-reset success/failure state
|
|
1617
|
+
require$$0.useEffect(() => {
|
|
1618
|
+
if ((wasSuccessful || wasFailed) && autoResetAfterMs) {
|
|
1619
|
+
const timeout = setTimeout(() => {
|
|
1620
|
+
setWasSuccessful(false);
|
|
1621
|
+
setWasFailed(false);
|
|
1622
|
+
if (failTimeoutRef.current) { // Clear fail timeout if still active
|
|
1623
|
+
clearTimeout(failTimeoutRef.current);
|
|
1624
|
+
failTimeoutRef.current = null;
|
|
1625
|
+
}
|
|
1626
|
+
}, autoResetAfterMs);
|
|
1627
|
+
return () => clearTimeout(timeout);
|
|
1628
|
+
}
|
|
1629
|
+
}, [wasSuccessful, wasFailed, autoResetAfterMs]);
|
|
1630
|
+
// Cleanup for failTimeoutRef on unmount
|
|
1631
|
+
require$$0.useEffect(() => {
|
|
1632
|
+
return () => {
|
|
1633
|
+
if (failTimeoutRef.current) {
|
|
1634
|
+
clearTimeout(failTimeoutRef.current);
|
|
1635
|
+
}
|
|
1636
|
+
};
|
|
1637
|
+
}, []);
|
|
1638
|
+
const startBusy = () => {
|
|
1639
|
+
setWasSuccessful(false);
|
|
1640
|
+
setWasFailed(false);
|
|
1641
|
+
setInternalBusy(true);
|
|
1642
|
+
};
|
|
1643
|
+
const endBusy = (isSuccess) => {
|
|
1644
|
+
setInternalBusy(false);
|
|
1645
|
+
if (isSuccess) {
|
|
1646
|
+
if (showCheckmark)
|
|
1647
|
+
setWasSuccessful(true);
|
|
1648
|
+
}
|
|
1649
|
+
else {
|
|
1650
|
+
if (showFailIcon)
|
|
1651
|
+
setWasFailed(true);
|
|
1652
|
+
// Bug 1: Clear any existing timeout before setting a new one
|
|
1653
|
+
if (failTimeoutRef.current) {
|
|
1654
|
+
clearTimeout(failTimeoutRef.current);
|
|
1655
|
+
}
|
|
1656
|
+
failTimeoutRef.current = setTimeout(() => {
|
|
1657
|
+
setWasFailed(false);
|
|
1658
|
+
failTimeoutRef.current = null; // Clear ref after timeout fires
|
|
1659
|
+
}, 400); // Shake animation duration
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
return {
|
|
1663
|
+
internalBusy,
|
|
1664
|
+
wasSuccessful,
|
|
1665
|
+
wasFailed,
|
|
1666
|
+
startBusy,
|
|
1667
|
+
endBusy,
|
|
1668
|
+
handleInternally,
|
|
1669
|
+
preventRageClick,
|
|
1670
|
+
minBusyDurationMs,
|
|
1671
|
+
showCheckmark,
|
|
1672
|
+
showFailIcon,
|
|
1673
|
+
autoResetAfterMs,
|
|
1674
|
+
failTimeoutRef // Expose this for ZestButton to clear if needed (e.g., confirmation failure)
|
|
1675
|
+
};
|
|
1676
|
+
};
|
|
1677
|
+
|
|
1678
|
+
const useConfirmation = ({ confirmOptions, originalChildren, onConfirmFail }) => {
|
|
1421
1679
|
const [awaitingConfirm, setAwaitingConfirm] = require$$0.useState(false);
|
|
1422
|
-
|
|
1680
|
+
const [currentChildren, setCurrentChildren] = require$$0.useState(originalChildren);
|
|
1423
1681
|
const confirmIntervalRef = require$$0.useRef(null);
|
|
1424
|
-
|
|
1682
|
+
require$$0.useEffect(() => {
|
|
1683
|
+
if (!awaitingConfirm) {
|
|
1684
|
+
setCurrentChildren(originalChildren);
|
|
1685
|
+
}
|
|
1686
|
+
}, [originalChildren, awaitingConfirm]);
|
|
1687
|
+
const stopConfirmation = require$$0.useCallback(() => {
|
|
1688
|
+
if (confirmIntervalRef.current) {
|
|
1689
|
+
clearInterval(confirmIntervalRef.current);
|
|
1690
|
+
confirmIntervalRef.current = null;
|
|
1691
|
+
}
|
|
1692
|
+
setCurrentChildren(originalChildren);
|
|
1693
|
+
setAwaitingConfirm(false);
|
|
1694
|
+
}, [originalChildren]);
|
|
1695
|
+
const startConfirmation = require$$0.useCallback(() => {
|
|
1696
|
+
if (!confirmOptions)
|
|
1697
|
+
return;
|
|
1698
|
+
setAwaitingConfirm(true);
|
|
1699
|
+
const { displayLabel, timeoutSecs } = confirmOptions;
|
|
1700
|
+
setCurrentChildren(`${displayLabel} (${timeoutSecs}s)`);
|
|
1701
|
+
const startTime = Date.now();
|
|
1702
|
+
confirmIntervalRef.current = setInterval(() => {
|
|
1703
|
+
const elapsed = Date.now() - startTime;
|
|
1704
|
+
const timeRemaining = timeoutSecs - Math.floor(elapsed / 1000);
|
|
1705
|
+
if (timeRemaining <= 0) {
|
|
1706
|
+
stopConfirmation();
|
|
1707
|
+
onConfirmFail?.();
|
|
1708
|
+
}
|
|
1709
|
+
else {
|
|
1710
|
+
setCurrentChildren(`${displayLabel} (${timeRemaining}s)`);
|
|
1711
|
+
}
|
|
1712
|
+
}, 1000);
|
|
1713
|
+
}, [confirmOptions, onConfirmFail, stopConfirmation]);
|
|
1714
|
+
require$$0.useEffect(() => {
|
|
1715
|
+
return () => {
|
|
1716
|
+
if (confirmIntervalRef.current) {
|
|
1717
|
+
clearInterval(confirmIntervalRef.current);
|
|
1718
|
+
}
|
|
1719
|
+
};
|
|
1720
|
+
}, []);
|
|
1721
|
+
return {
|
|
1722
|
+
awaitingConfirm,
|
|
1723
|
+
currentChildren,
|
|
1724
|
+
startConfirmation,
|
|
1725
|
+
stopConfirmation,
|
|
1726
|
+
};
|
|
1727
|
+
};
|
|
1728
|
+
|
|
1729
|
+
const useThemeDetection = () => {
|
|
1425
1730
|
const [systemTheme, setSystemTheme] = require$$0.useState('light');
|
|
1426
1731
|
require$$0.useEffect(() => {
|
|
1427
1732
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
@@ -1432,13 +1737,25 @@ zest, // New parent prop
|
|
|
1432
1737
|
mediaQuery.addEventListener('change', handleChange);
|
|
1433
1738
|
return () => mediaQuery.removeEventListener('change', handleChange);
|
|
1434
1739
|
}, []);
|
|
1740
|
+
return systemTheme;
|
|
1741
|
+
};
|
|
1742
|
+
|
|
1743
|
+
// --- Components ---
|
|
1744
|
+
const AnimatedCheckmark = () => (jsxRuntimeExports.jsx("svg", { className: styles.animatedCheck, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("path", { d: "M5 13l4 4L19 7" }) }));
|
|
1745
|
+
const AnimatedX = () => (jsxRuntimeExports.jsxs("svg", { className: styles.animatedX, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M6 6L18 18" }), jsxRuntimeExports.jsx("path", { d: "M6 18L18 6" })] }));
|
|
1746
|
+
const ZestButton = ({ className = "", disabled, children, onClick, zest: localZestProps, ...props }) => {
|
|
1747
|
+
const effectiveZestConfig = useZestConfig(localZestProps);
|
|
1748
|
+
const { visualOptions = {}, busyOptions = {}, successOptions = {}, confirmOptions, isDefault = false, theme = 'system', buttonStyle = 'solid', } = effectiveZestConfig;
|
|
1749
|
+
const { variant = "standard", size = "md", fullWidth = false, iconLeft, iconRight, } = visualOptions;
|
|
1750
|
+
const { handleInternally, minBusyDurationMs, preventRageClick, showCheckmark, showFailIcon, internalBusy, wasSuccessful, wasFailed, startBusy, endBusy, } = useBusyState({ busyOptions, successOptions });
|
|
1751
|
+
const { awaitingConfirm, currentChildren, startConfirmation, stopConfirmation, } = useConfirmation({
|
|
1752
|
+
confirmOptions,
|
|
1753
|
+
originalChildren: children,
|
|
1754
|
+
onConfirmFail: () => endBusy(false),
|
|
1755
|
+
});
|
|
1756
|
+
const buttonRef = require$$0.useRef(null);
|
|
1757
|
+
const systemTheme = useThemeDetection();
|
|
1435
1758
|
const effectiveTheme = theme === 'system' ? systemTheme : theme;
|
|
1436
|
-
// keep children in sync when not in confirm mode
|
|
1437
|
-
require$$0.useEffect(() => {
|
|
1438
|
-
if (!awaitingConfirm) {
|
|
1439
|
-
setCurrentChildren(children);
|
|
1440
|
-
}
|
|
1441
|
-
}, [children, awaitingConfirm]);
|
|
1442
1759
|
const effectiveBusy = typeof props["aria-busy"] === "boolean"
|
|
1443
1760
|
? Boolean(props["aria-busy"])
|
|
1444
1761
|
: handleInternally
|
|
@@ -1447,23 +1764,12 @@ zest, // New parent prop
|
|
|
1447
1764
|
const isDisabled = disabled ||
|
|
1448
1765
|
effectiveBusy ||
|
|
1449
1766
|
(preventRageClick && (wasSuccessful || wasFailed));
|
|
1450
|
-
// Move handleClick, stopWaiting, and handleConfirmClick declarations here
|
|
1451
|
-
const stopWaiting = () => {
|
|
1452
|
-
if (confirmIntervalRef.current) {
|
|
1453
|
-
clearInterval(confirmIntervalRef.current);
|
|
1454
|
-
confirmIntervalRef.current = null;
|
|
1455
|
-
}
|
|
1456
|
-
setCurrentChildren(children);
|
|
1457
|
-
setAwaitingConfirm(false);
|
|
1458
|
-
};
|
|
1459
1767
|
const handleClick = async (e) => {
|
|
1460
1768
|
if (preventRageClick && internalBusy)
|
|
1461
1769
|
return;
|
|
1462
1770
|
if (handleInternally && typeof onClick === "function") {
|
|
1463
1771
|
try {
|
|
1464
|
-
|
|
1465
|
-
setWasFailed(false);
|
|
1466
|
-
setInternalBusy(true);
|
|
1772
|
+
startBusy();
|
|
1467
1773
|
const startTime = Date.now();
|
|
1468
1774
|
await onClick(e);
|
|
1469
1775
|
const elapsed = Date.now() - startTime;
|
|
@@ -1471,69 +1777,33 @@ zest, // New parent prop
|
|
|
1471
1777
|
if (remaining > 0) {
|
|
1472
1778
|
await new Promise((resolve) => setTimeout(resolve, remaining));
|
|
1473
1779
|
}
|
|
1474
|
-
|
|
1475
|
-
setWasSuccessful(true);
|
|
1780
|
+
endBusy(true);
|
|
1476
1781
|
}
|
|
1477
1782
|
catch (err) {
|
|
1478
1783
|
console.error(err);
|
|
1479
|
-
|
|
1480
|
-
setWasFailed(true);
|
|
1481
|
-
}
|
|
1482
|
-
finally {
|
|
1483
|
-
setInternalBusy(false);
|
|
1784
|
+
endBusy(false);
|
|
1484
1785
|
}
|
|
1485
1786
|
}
|
|
1486
1787
|
else if (onClick) {
|
|
1487
1788
|
onClick(e);
|
|
1488
1789
|
}
|
|
1489
1790
|
};
|
|
1490
|
-
const handleConfirmClick =
|
|
1491
|
-
if (!confirmOptions) { // Use destructured confirmOptions
|
|
1492
|
-
return handleClick(e);
|
|
1493
|
-
}
|
|
1494
|
-
// Edge Case 3: Add warning for missing onClick with confirmOptions
|
|
1495
|
-
if (confirmOptions && !onClick) { // Use destructured confirmOptions and onClick
|
|
1496
|
-
console.warn("ZestButton: 'confirmOptions' are provided but 'onClick' handler is missing. The button will confirm but perform no action.");
|
|
1497
|
-
}
|
|
1791
|
+
const handleConfirmClick = (e) => {
|
|
1498
1792
|
if (awaitingConfirm) {
|
|
1499
|
-
|
|
1500
|
-
|
|
1793
|
+
stopConfirmation();
|
|
1794
|
+
handleClick(e);
|
|
1795
|
+
return;
|
|
1501
1796
|
}
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
setCurrentChildren(`${displayLabel} (${timeoutSecs}s)`); // Initial display
|
|
1506
|
-
confirmIntervalRef.current = setInterval(() => {
|
|
1507
|
-
const elapsed = Date.now() - startTime;
|
|
1508
|
-
const timeRemaining = timeoutSecs - Math.floor(elapsed / 1000);
|
|
1509
|
-
if (timeRemaining <= 0) {
|
|
1510
|
-
stopWaiting();
|
|
1511
|
-
setWasFailed(true); // Indicate failure for shake animation
|
|
1512
|
-
// Bug 1: Clear any existing timeout before setting a new one
|
|
1513
|
-
if (failTimeoutRef.current) {
|
|
1514
|
-
clearTimeout(failTimeoutRef.current);
|
|
1515
|
-
}
|
|
1516
|
-
failTimeoutRef.current = setTimeout(() => {
|
|
1517
|
-
setWasFailed(false);
|
|
1518
|
-
failTimeoutRef.current = null; // Clear ref after timeout fires
|
|
1519
|
-
}, 400); // Shake animation duration
|
|
1520
|
-
}
|
|
1521
|
-
else {
|
|
1522
|
-
setCurrentChildren(`${displayLabel} (${timeRemaining}s)`);
|
|
1797
|
+
if (confirmOptions) {
|
|
1798
|
+
if (!onClick) {
|
|
1799
|
+
console.warn("ZestButton: 'confirmOptions' are provided but 'onClick' handler is missing.");
|
|
1523
1800
|
}
|
|
1524
|
-
|
|
1525
|
-
};
|
|
1526
|
-
// auto-reset success/failure state
|
|
1527
|
-
require$$0.useEffect(() => {
|
|
1528
|
-
if ((wasSuccessful || wasFailed) && autoResetAfterMs) {
|
|
1529
|
-
const timeout = setTimeout(() => {
|
|
1530
|
-
setWasSuccessful(false);
|
|
1531
|
-
setWasFailed(false);
|
|
1532
|
-
}, autoResetAfterMs);
|
|
1533
|
-
return () => clearTimeout(timeout);
|
|
1801
|
+
startConfirmation();
|
|
1534
1802
|
}
|
|
1535
|
-
|
|
1536
|
-
|
|
1803
|
+
else {
|
|
1804
|
+
handleClick(e);
|
|
1805
|
+
}
|
|
1806
|
+
};
|
|
1537
1807
|
require$$0.useEffect(() => {
|
|
1538
1808
|
if (!isDefault || isDisabled)
|
|
1539
1809
|
return;
|
|
@@ -1542,54 +1812,50 @@ zest, // New parent prop
|
|
|
1542
1812
|
if (e.key === "Enter" &&
|
|
1543
1813
|
!e.repeat &&
|
|
1544
1814
|
!e.defaultPrevented &&
|
|
1545
|
-
!(target instanceof HTMLTextAreaElement)
|
|
1815
|
+
!(target instanceof HTMLTextAreaElement) &&
|
|
1816
|
+
buttonRef.current &&
|
|
1817
|
+
document.activeElement !== buttonRef.current // Optional: prevent double-action if button is focused
|
|
1818
|
+
) {
|
|
1546
1819
|
e.preventDefault();
|
|
1547
|
-
|
|
1548
|
-
handleConfirmClick(e);
|
|
1820
|
+
buttonRef.current.click();
|
|
1549
1821
|
}
|
|
1550
1822
|
};
|
|
1551
1823
|
document.addEventListener("keydown", listener);
|
|
1552
1824
|
return () => document.removeEventListener("keydown", listener);
|
|
1553
|
-
}, [isDefault, isDisabled
|
|
1554
|
-
// cleanup on unmount
|
|
1555
|
-
require$$0.useEffect(() => {
|
|
1556
|
-
return () => {
|
|
1557
|
-
if (confirmIntervalRef.current) {
|
|
1558
|
-
clearInterval(confirmIntervalRef.current);
|
|
1559
|
-
}
|
|
1560
|
-
// Bug 1: Add cleanup for failTimeoutRef
|
|
1561
|
-
if (failTimeoutRef.current) {
|
|
1562
|
-
clearTimeout(failTimeoutRef.current);
|
|
1563
|
-
}
|
|
1564
|
-
};
|
|
1565
|
-
}, []);
|
|
1825
|
+
}, [isDefault, isDisabled]);
|
|
1566
1826
|
const renderLeftIcon = () => {
|
|
1567
1827
|
if (effectiveBusy) {
|
|
1568
1828
|
return (jsxRuntimeExports.jsx("span", { className: `${styles.icon} ${styles.fadeIn}`, children: jsxRuntimeExports.jsx(fa6.FaSpinner, { className: styles.spinner }) }));
|
|
1569
1829
|
}
|
|
1570
|
-
|
|
1830
|
+
if (wasSuccessful && showCheckmark) {
|
|
1571
1831
|
return (jsxRuntimeExports.jsx("span", { className: `${styles.icon} ${styles.fadeIn}`, children: jsxRuntimeExports.jsx(AnimatedCheckmark, {}) }));
|
|
1572
1832
|
}
|
|
1573
|
-
|
|
1833
|
+
if (wasFailed && showFailIcon) {
|
|
1574
1834
|
return (jsxRuntimeExports.jsx("span", { className: `${styles.icon} ${styles.fadeIn}`, children: jsxRuntimeExports.jsx(AnimatedX, {}) }));
|
|
1575
1835
|
}
|
|
1576
|
-
|
|
1836
|
+
if (iconLeft) {
|
|
1577
1837
|
return jsxRuntimeExports.jsx("span", { className: styles.icon, children: iconLeft });
|
|
1578
1838
|
}
|
|
1579
1839
|
return null;
|
|
1580
1840
|
};
|
|
1581
1841
|
return (jsxRuntimeExports.jsx("button", { ref: buttonRef, className: [
|
|
1582
1842
|
styles.button,
|
|
1583
|
-
styles[buttonStyle],
|
|
1843
|
+
styles[buttonStyle],
|
|
1584
1844
|
styles[variant],
|
|
1585
1845
|
styles[size],
|
|
1586
1846
|
fullWidth ? styles.fullWidth : "",
|
|
1587
1847
|
isDisabled ? styles.disabled : "",
|
|
1588
1848
|
wasFailed ? styles.shake : "",
|
|
1589
|
-
effectiveTheme === 'light' ? styles['force-light'] : styles['force-dark'],
|
|
1849
|
+
effectiveTheme === 'light' ? styles['force-light'] : styles['force-dark'],
|
|
1590
1850
|
className,
|
|
1591
1851
|
].join(" "), disabled: isDisabled, "aria-busy": effectiveBusy, onClick: handleConfirmClick, ...props, children: jsxRuntimeExports.jsxs("span", { className: styles.inner, children: [renderLeftIcon(), jsxRuntimeExports.jsxs("span", { className: styles.content, children: [currentChildren, iconRight && jsxRuntimeExports.jsx("span", { className: styles.icon, children: iconRight })] })] }) }));
|
|
1592
1852
|
};
|
|
1593
1853
|
|
|
1594
|
-
|
|
1854
|
+
const ZestProvider = ({ config, children }) => {
|
|
1855
|
+
return (jsxRuntimeExports.jsx(ZestContext.Provider, { value: config, children: children }));
|
|
1856
|
+
};
|
|
1857
|
+
|
|
1858
|
+
exports.ZestButton = ZestButton;
|
|
1859
|
+
exports.ZestProvider = ZestProvider;
|
|
1860
|
+
exports.useZest = useZest;
|
|
1595
1861
|
//# sourceMappingURL=index.cjs.js.map
|