@take-out/helpers 0.0.40 → 0.0.42

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.
Files changed (171) hide show
  1. package/dist/cjs/async/asyncContext.cjs +7 -16
  2. package/dist/cjs/async/asyncContext.js +7 -11
  3. package/dist/cjs/async/asyncContext.js.map +1 -1
  4. package/dist/cjs/async/asyncContext.native.js +10 -12
  5. package/dist/cjs/async/asyncContext.native.js.map +1 -1
  6. package/dist/cjs/clipboard/clipboard.cjs +32 -0
  7. package/dist/cjs/clipboard/clipboard.js +27 -0
  8. package/dist/cjs/clipboard/clipboard.js.map +6 -0
  9. package/dist/cjs/clipboard/clipboard.native.js +41 -0
  10. package/dist/cjs/clipboard/clipboard.native.js.map +6 -0
  11. package/dist/cjs/clipboard/index.cjs +18 -0
  12. package/dist/cjs/clipboard/index.js +15 -0
  13. package/dist/cjs/clipboard/index.js.map +6 -0
  14. package/dist/cjs/clipboard/index.native.js +20 -0
  15. package/dist/cjs/clipboard/index.native.js.map +6 -0
  16. package/dist/cjs/color/extractOpacityFromColor.cjs +34 -0
  17. package/dist/cjs/color/extractOpacityFromColor.js +29 -0
  18. package/dist/cjs/color/extractOpacityFromColor.js.map +6 -0
  19. package/dist/cjs/color/extractOpacityFromColor.native.js +38 -0
  20. package/dist/cjs/color/extractOpacityFromColor.native.js.map +6 -0
  21. package/dist/cjs/color/generateColors.cjs +77 -0
  22. package/dist/cjs/color/generateColors.js +64 -0
  23. package/dist/cjs/color/generateColors.js.map +6 -0
  24. package/dist/cjs/color/generateColors.native.js +88 -0
  25. package/dist/cjs/color/generateColors.native.js.map +6 -0
  26. package/dist/cjs/color/index.cjs +21 -0
  27. package/dist/cjs/color/index.js +18 -0
  28. package/dist/cjs/color/index.js.map +6 -0
  29. package/dist/cjs/color/index.native.js +26 -0
  30. package/dist/cjs/color/index.native.js.map +6 -0
  31. package/dist/cjs/color/lum.cjs +75 -0
  32. package/dist/cjs/color/lum.js +61 -0
  33. package/dist/cjs/color/lum.js.map +6 -0
  34. package/dist/cjs/color/lum.native.js +70 -0
  35. package/dist/cjs/color/lum.native.js.map +6 -0
  36. package/dist/cjs/color/toHex.cjs +32 -0
  37. package/dist/cjs/color/toHex.js +27 -0
  38. package/dist/cjs/color/toHex.js.map +6 -0
  39. package/dist/cjs/color/toHex.native.js +33 -0
  40. package/dist/cjs/color/toHex.native.js.map +6 -0
  41. package/dist/cjs/index.cjs +7 -0
  42. package/dist/cjs/index.js +7 -0
  43. package/dist/cjs/index.js.map +1 -1
  44. package/dist/cjs/index.native.js +14 -0
  45. package/dist/cjs/index.native.js.map +1 -1
  46. package/dist/cjs/number/formatNumber.cjs +9 -1
  47. package/dist/cjs/number/formatNumber.js +9 -1
  48. package/dist/cjs/number/formatNumber.js.map +1 -1
  49. package/dist/cjs/number/formatNumber.native.js +12 -2
  50. package/dist/cjs/number/formatNumber.native.js.map +1 -1
  51. package/dist/cjs/time/formatDistanceToNow.cjs +32 -0
  52. package/dist/cjs/time/formatDistanceToNow.js +24 -0
  53. package/dist/cjs/time/formatDistanceToNow.js.map +6 -0
  54. package/dist/cjs/time/formatDistanceToNow.native.js +29 -0
  55. package/dist/cjs/time/formatDistanceToNow.native.js.map +6 -0
  56. package/dist/cjs/time/useTimer.cjs +55 -0
  57. package/dist/cjs/time/useTimer.js +51 -0
  58. package/dist/cjs/time/useTimer.js.map +6 -0
  59. package/dist/cjs/time/useTimer.native.js +67 -0
  60. package/dist/cjs/time/useTimer.native.js.map +6 -0
  61. package/dist/esm/async/asyncContext.js +5 -1
  62. package/dist/esm/async/asyncContext.js.map +1 -1
  63. package/dist/esm/async/asyncContext.mjs +3 -1
  64. package/dist/esm/async/asyncContext.mjs.map +1 -1
  65. package/dist/esm/async/asyncContext.native.js +4 -2
  66. package/dist/esm/async/asyncContext.native.js.map +1 -1
  67. package/dist/esm/clipboard/clipboard.js +11 -0
  68. package/dist/esm/clipboard/clipboard.js.map +6 -0
  69. package/dist/esm/clipboard/clipboard.mjs +9 -0
  70. package/dist/esm/clipboard/clipboard.mjs.map +1 -0
  71. package/dist/esm/clipboard/clipboard.native.js +11 -0
  72. package/dist/esm/clipboard/clipboard.native.js.map +1 -0
  73. package/dist/esm/clipboard/index.js +2 -0
  74. package/dist/esm/clipboard/index.js.map +6 -0
  75. package/dist/esm/clipboard/index.mjs +2 -0
  76. package/dist/esm/clipboard/index.mjs.map +1 -0
  77. package/dist/esm/clipboard/index.native.js +2 -0
  78. package/dist/esm/clipboard/index.native.js.map +1 -0
  79. package/dist/esm/color/extractOpacityFromColor.js +13 -0
  80. package/dist/esm/color/extractOpacityFromColor.js.map +6 -0
  81. package/dist/esm/color/extractOpacityFromColor.mjs +11 -0
  82. package/dist/esm/color/extractOpacityFromColor.mjs.map +1 -0
  83. package/dist/esm/color/extractOpacityFromColor.native.js +15 -0
  84. package/dist/esm/color/extractOpacityFromColor.native.js.map +1 -0
  85. package/dist/esm/color/generateColors.js +48 -0
  86. package/dist/esm/color/generateColors.js.map +6 -0
  87. package/dist/esm/color/generateColors.mjs +54 -0
  88. package/dist/esm/color/generateColors.mjs.map +1 -0
  89. package/dist/esm/color/generateColors.native.js +52 -0
  90. package/dist/esm/color/generateColors.native.js.map +1 -0
  91. package/dist/esm/color/index.js +5 -0
  92. package/dist/esm/color/index.js.map +6 -0
  93. package/dist/esm/color/index.mjs +5 -0
  94. package/dist/esm/color/index.mjs.map +1 -0
  95. package/dist/esm/color/index.native.js +5 -0
  96. package/dist/esm/color/index.native.js.map +1 -0
  97. package/dist/esm/color/lum.js +45 -0
  98. package/dist/esm/color/lum.js.map +6 -0
  99. package/dist/esm/color/lum.mjs +52 -0
  100. package/dist/esm/color/lum.mjs.map +1 -0
  101. package/dist/esm/color/lum.native.js +57 -0
  102. package/dist/esm/color/lum.native.js.map +1 -0
  103. package/dist/esm/color/toHex.js +11 -0
  104. package/dist/esm/color/toHex.js.map +6 -0
  105. package/dist/esm/color/toHex.mjs +8 -0
  106. package/dist/esm/color/toHex.mjs.map +1 -0
  107. package/dist/esm/color/toHex.native.js +8 -0
  108. package/dist/esm/color/toHex.native.js.map +1 -0
  109. package/dist/esm/index.js +7 -0
  110. package/dist/esm/index.js.map +1 -1
  111. package/dist/esm/index.mjs +7 -0
  112. package/dist/esm/index.mjs.map +1 -1
  113. package/dist/esm/index.native.js +7 -0
  114. package/dist/esm/index.native.js.map +1 -1
  115. package/dist/esm/number/formatNumber.js +9 -1
  116. package/dist/esm/number/formatNumber.js.map +1 -1
  117. package/dist/esm/number/formatNumber.mjs +7 -1
  118. package/dist/esm/number/formatNumber.mjs.map +1 -1
  119. package/dist/esm/number/formatNumber.native.js +7 -1
  120. package/dist/esm/number/formatNumber.native.js.map +1 -1
  121. package/dist/esm/time/formatDistanceToNow.js +8 -0
  122. package/dist/esm/time/formatDistanceToNow.js.map +6 -0
  123. package/dist/esm/time/formatDistanceToNow.mjs +9 -0
  124. package/dist/esm/time/formatDistanceToNow.mjs.map +1 -0
  125. package/dist/esm/time/formatDistanceToNow.native.js +10 -0
  126. package/dist/esm/time/formatDistanceToNow.native.js.map +1 -0
  127. package/dist/esm/time/useTimer.js +35 -0
  128. package/dist/esm/time/useTimer.js.map +6 -0
  129. package/dist/esm/time/useTimer.mjs +32 -0
  130. package/dist/esm/time/useTimer.mjs.map +1 -0
  131. package/dist/esm/time/useTimer.native.js +40 -0
  132. package/dist/esm/time/useTimer.native.js.map +1 -0
  133. package/package.json +2 -1
  134. package/src/async/asyncContext.ts +4 -1
  135. package/src/clipboard/clipboard.native.ts +10 -0
  136. package/src/clipboard/clipboard.ts +8 -0
  137. package/src/color/extractOpacityFromColor.ts +18 -0
  138. package/src/color/generateColors.ts +72 -0
  139. package/src/color/lum.ts +78 -0
  140. package/src/color/toHex.ts +10 -0
  141. package/src/index.ts +11 -0
  142. package/src/number/formatNumber.ts +15 -0
  143. package/src/time/formatDistanceToNow.ts +17 -0
  144. package/src/time/useTimer.ts +80 -0
  145. package/types/async/asyncContext.d.ts.map +2 -2
  146. package/types/async/asyncContext.native.d.ts +9 -0
  147. package/types/async/asyncContext.native.d.ts.map +14 -0
  148. package/types/clipboard/clipboard.d.ts +3 -0
  149. package/types/clipboard/clipboard.d.ts.map +11 -0
  150. package/types/clipboard/clipboard.native.d.ts +3 -0
  151. package/types/clipboard/clipboard.native.d.ts.map +11 -0
  152. package/types/clipboard/index.d.ts +3 -0
  153. package/types/clipboard/index.d.ts.map +11 -0
  154. package/types/color/extractOpacityFromColor.d.ts +3 -0
  155. package/types/color/extractOpacityFromColor.d.ts.map +13 -0
  156. package/types/color/generateColors.d.ts +11 -0
  157. package/types/color/generateColors.d.ts.map +11 -0
  158. package/types/color/index.d.ts +6 -0
  159. package/types/color/index.d.ts.map +11 -0
  160. package/types/color/lum.d.ts +3 -0
  161. package/types/color/lum.d.ts.map +13 -0
  162. package/types/color/toHex.d.ts +6 -0
  163. package/types/color/toHex.d.ts.map +13 -0
  164. package/types/index.d.ts +9 -0
  165. package/types/index.d.ts.map +2 -2
  166. package/types/number/formatNumber.d.ts +2 -0
  167. package/types/number/formatNumber.d.ts.map +5 -3
  168. package/types/time/formatDistanceToNow.d.ts +3 -0
  169. package/types/time/formatDistanceToNow.d.ts.map +13 -0
  170. package/types/time/useTimer.d.ts +11 -0
  171. package/types/time/useTimer.d.ts.map +14 -0
@@ -1 +1 @@
1
- {"version":3,"names":["formatNumber","value","options","arguments","length","locale","maximumFractionDigits","minimumFractionDigits","forceCompact","Math","abs","Intl","NumberFormat","format","notation","compactDisplay","abbreviateNumber","formatCount"],"sources":["../../../src/number/formatNumber.ts"],"sourcesContent":[null],"mappings":"AAOO,SAASA,aAAaC,KAAA,EAAe;EAC1C,IAAAC,OAAM,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,iBAAAA,SAAA;IAAA;MAAAE,MAAA;MAAAC,qBAAA;MAAAC,qBAAA;MAAAC,YAAA;IAAA,IAAAN,OAAA;EAAA,OACJ,CAAAM,YAAS,IAAAC,IAAA,CAAAC,GAAA,CAAAT,KAAA,cAAAU,IAAA,CAAAC,YAAA,CAAAP,MAAA;IACTC,qBAAA;IACAC;EAAwB,EACxB,CAAAM,MAAA,CAAAZ,KAAA,IAAe,IAAAU,IAAA,CAAAC,YAAA,CAAAP,MAAA;IACjBS,QAAI;IAEJC,cAAK,SAAgB;IAEjBT,qBAAA;IACAC;EACF,CAAC,EAAEM,MAAA,CAAOZ,KAAK;AAGoB;AACzB,SACVe,gBAAgBA,CAAAf,KAAA;EAAA,OAChBD,YAAA,CAAAC,KAAA;IACAK,qBAAA;EACF,CAAC;AACH;AAEO,SAASW,YAAAhB,KAAiB;EAC/B,OAAOD,YAAA,CAAaC,KAAA,EAAO;IAC7BK,qBAAA;IAEOE,YAAS,EAAAP,KAAY;EAC1B;AAA2B;AACF,SAEzBe,gBAAC,EACHC,WAAA,E","ignoreList":[]}
1
+ {"version":3,"names":["formatNumber","value","options","arguments","length","locale","maximumFractionDigits","minimumFractionDigits","forceCompact","Math","abs","Intl","NumberFormat","format","notation","compactDisplay","abbreviateNumber","formatCount","formatReactionCount","toFixed","toString","formatPhoneNumber"],"sources":["../../../src/number/formatNumber.ts"],"sourcesContent":[null],"mappings":"AAOO,SAASA,aAAaC,KAAA,EAAe;EAC1C,IAAAC,OAAM,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,iBAAAA,SAAA;IAAA;MAAAE,MAAA;MAAAC,qBAAA;MAAAC,qBAAA;MAAAC,YAAA;IAAA,IAAAN,OAAA;EAAA,OACJ,CAAAM,YAAS,IAAAC,IAAA,CAAAC,GAAA,CAAAT,KAAA,cAAAU,IAAA,CAAAC,YAAA,CAAAP,MAAA;IACTC,qBAAA;IACAC;EAAwB,EACxB,CAAAM,MAAA,CAAAZ,KAAA,IAAe,IAAAU,IAAA,CAAAC,YAAA,CAAAP,MAAA;IACjBS,QAAI;IAEJC,cAAK,SAAgB;IAEjBT,qBAAA;IACAC;EACF,CAAC,EAAEM,MAAA,CAAOZ,KAAK;AAGoB;AACzB,SACVe,gBAAgBA,CAAAf,KAAA;EAAA,OAChBD,YAAA,CAAAC,KAAA;IACAK,qBAAA;EACF,CAAC;AACH;AAEO,SAASW,YAAAhB,KAAiB;EAC/B,OAAOD,YAAA,CAAaC,KAAA,EAAO;IAC7BK,qBAAA;IAEOE,YAAS,EAAAP,KAAY;EAC1B;AAA2B;AACF,SACvBiB,mBAAuBA,CAAAjB,KAAA;EACzB,OAAC,OAAAA,KAAA,eAAAA,KAAA,GAAAA,KAAA,cAAAA,KAAA,QAAAkB,OAAA,SAAAlB,KAAA,cAAAA,KAAA,QAAAkB,OAAA,SAAAlB,KAAA,CAAAmB,QAAA;AACH;AAEO,SAASC,kBAAApB,KAAoB;EAClC,OAAIA,KAAA;AAQN;AAEO,SACLe,gBAAO,EACTC,WAAA,E","ignoreList":[]}
@@ -0,0 +1,8 @@
1
+ function formatDistanceToNow(timestamp) {
2
+ const diff = Date.now() - timestamp, minutes = Math.floor(diff / 6e4), hours = Math.floor(diff / 36e5), days = Math.floor(diff / 864e5);
3
+ return minutes < 1 ? "just now" : minutes < 60 ? `${minutes}m` : hours < 24 ? `${hours}h` : days < 7 ? `${days}d` : days < 30 ? `${Math.floor(days / 7)}w` : days < 365 ? `${Math.floor(days / 30)}mo` : `${Math.floor(days / 365)}y`;
4
+ }
5
+ export {
6
+ formatDistanceToNow
7
+ };
8
+ //# sourceMappingURL=formatDistanceToNow.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/time/formatDistanceToNow.ts"],
4
+ "mappings": "AAAO,SAAS,oBAAoB,WAA2B;AAE7D,QAAM,OADM,KAAK,IAAI,IACF,WAEb,UAAU,KAAK,MAAM,OAAO,GAAK,GACjC,QAAQ,KAAK,MAAM,OAAO,IAAO,GACjC,OAAO,KAAK,MAAM,OAAO,KAAQ;AAEvC,SAAI,UAAU,IAAU,aACpB,UAAU,KAAW,GAAG,OAAO,MAC/B,QAAQ,KAAW,GAAG,KAAK,MAC3B,OAAO,IAAU,GAAG,IAAI,MACxB,OAAO,KAAW,GAAG,KAAK,MAAM,OAAO,CAAC,CAAC,MACzC,OAAO,MAAY,GAAG,KAAK,MAAM,OAAO,EAAE,CAAC,OAExC,GAAG,KAAK,MAAM,OAAO,GAAG,CAAC;AAClC;",
5
+ "names": []
6
+ }
@@ -0,0 +1,9 @@
1
+ function formatDistanceToNow(timestamp) {
2
+ const diff = Date.now() - timestamp,
3
+ minutes = Math.floor(diff / 6e4),
4
+ hours = Math.floor(diff / 36e5),
5
+ days = Math.floor(diff / 864e5);
6
+ return minutes < 1 ? "just now" : minutes < 60 ? `${minutes}m` : hours < 24 ? `${hours}h` : days < 7 ? `${days}d` : days < 30 ? `${Math.floor(days / 7)}w` : days < 365 ? `${Math.floor(days / 30)}mo` : `${Math.floor(days / 365)}y`;
7
+ }
8
+ export { formatDistanceToNow };
9
+ //# sourceMappingURL=formatDistanceToNow.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["formatDistanceToNow","timestamp","diff","Date","now","minutes","Math","floor","hours","days"],"sources":["../../../src/time/formatDistanceToNow.ts"],"sourcesContent":[null],"mappings":"AAAO,SAASA,oBAAoBC,SAAA,EAA2B;EAE7D,MAAMC,IAAA,GADMC,IAAA,CAAKC,GAAA,CAAI,IACFH,SAAA;IAEbI,OAAA,GAAUC,IAAA,CAAKC,KAAA,CAAML,IAAA,GAAO,GAAK;IACjCM,KAAA,GAAQF,IAAA,CAAKC,KAAA,CAAML,IAAA,GAAO,IAAO;IACjCO,IAAA,GAAOH,IAAA,CAAKC,KAAA,CAAML,IAAA,GAAO,KAAQ;EAEvC,OAAIG,OAAA,GAAU,IAAU,aACpBA,OAAA,GAAU,KAAW,GAAGA,OAAO,MAC/BG,KAAA,GAAQ,KAAW,GAAGA,KAAK,MAC3BC,IAAA,GAAO,IAAU,GAAGA,IAAI,MACxBA,IAAA,GAAO,KAAW,GAAGH,IAAA,CAAKC,KAAA,CAAME,IAAA,GAAO,CAAC,CAAC,MACzCA,IAAA,GAAO,MAAY,GAAGH,IAAA,CAAKC,KAAA,CAAME,IAAA,GAAO,EAAE,CAAC,OAExC,GAAGH,IAAA,CAAKC,KAAA,CAAME,IAAA,GAAO,GAAG,CAAC;AAClC","ignoreList":[]}
@@ -0,0 +1,10 @@
1
+ function formatDistanceToNow(timestamp) {
2
+ var now = Date.now(),
3
+ diff = now - timestamp,
4
+ minutes = Math.floor(diff / 6e4),
5
+ hours = Math.floor(diff / 36e5),
6
+ days = Math.floor(diff / 864e5);
7
+ return minutes < 1 ? "just now" : minutes < 60 ? `${minutes}m` : hours < 24 ? `${hours}h` : days < 7 ? `${days}d` : days < 30 ? `${Math.floor(days / 7)}w` : days < 365 ? `${Math.floor(days / 30)}mo` : `${Math.floor(days / 365)}y`;
8
+ }
9
+ export { formatDistanceToNow };
10
+ //# sourceMappingURL=formatDistanceToNow.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["formatDistanceToNow","timestamp","now","Date","diff","minutes","Math","floor","hours","days"],"sources":["../../../src/time/formatDistanceToNow.ts"],"sourcesContent":[null],"mappings":"AAAO,SAASA,oBAAoBC,SAAA,EAA2B;EAE7D,IAAAC,GAAM,GAAAC,IADM,CAAAD,GAAK;IAAIE,IACF,GAAAF,GAAA,GAAAD,SAEb;IAAAI,OAAe,GAAAC,IAAM,CAAAC,KAAO,CAAAH,IAC5B;IAAQI,KAAK,GAAAF,IAAM,CAAAC,KAAO,CAAAH,IAAO,GACjC,KAAO;IAAAK,IAAK,GAAAH,IAAM,CAAAC,KAAO,CAAAH,IAAQ;EAEvC,OAAIC,OAAA,GAAU,IAAU,aACpBA,OAAA,GAAU,KAAW,GAAGA,OAAO,MAC/BG,KAAA,GAAQ,KAAW,GAAGA,KAAK,MAC3BC,IAAA,GAAO,IAAU,GAAGA,IAAI,MACxBA,IAAA,GAAO,KAAW,GAAGH,IAAA,CAAKC,KAAA,CAAME,IAAA,GAAO,CAAC,CAAC,MACzCA,IAAA,GAAO,MAAY,GAAGH,IAAA,CAAKC,KAAA,CAAME,IAAA,GAAO,EAAE,CAAC,OAExC,GAAGH,IAAA,CAAKC,KAAA,CAAME,IAAA,GAAO,GAAG,CAAC;AAClC","ignoreList":[]}
@@ -0,0 +1,35 @@
1
+ import { useState, useEffect, useRef, useMemo, useCallback } from "react";
2
+ const useTimer = () => {
3
+ const [timerCount, setTimer] = useState(30), intervalRef = useRef(null), clearTimer = useCallback(() => {
4
+ intervalRef.current && (clearInterval(intervalRef.current), intervalRef.current = null);
5
+ }, []), resetTimer = useCallback(
6
+ (time, start) => {
7
+ setTimer(time), clearTimer(), start && (intervalRef.current = setInterval(() => {
8
+ setTimer((lastTimerCount) => lastTimerCount <= 1 ? (clearInterval(intervalRef.current), intervalRef.current = null, 0) : lastTimerCount - 1);
9
+ }, 1e3));
10
+ },
11
+ [clearTimer]
12
+ ), pauseTimer = useCallback(() => {
13
+ clearTimer();
14
+ }, [clearTimer]), resumeTimer = useCallback(() => {
15
+ intervalRef.current || (intervalRef.current = setInterval(() => {
16
+ setTimer((lastTimerCount) => lastTimerCount <= 1 ? (clearInterval(intervalRef.current), intervalRef.current = null, 0) : lastTimerCount - 1);
17
+ }, 1e3));
18
+ }, []);
19
+ return useEffect(() => () => {
20
+ intervalRef.current && (clearInterval(intervalRef.current), intervalRef.current = null);
21
+ }, []), useMemo(
22
+ () => ({
23
+ count: timerCount,
24
+ start: resetTimer,
25
+ pause: pauseTimer,
26
+ resume: resumeTimer,
27
+ clear: clearTimer
28
+ }),
29
+ [timerCount, clearTimer, pauseTimer, resetTimer, resumeTimer]
30
+ );
31
+ };
32
+ export {
33
+ useTimer
34
+ };
35
+ //# sourceMappingURL=useTimer.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/time/useTimer.ts"],
4
+ "mappings": "AAAA,SAAS,UAAU,WAAW,QAAQ,SAAS,mBAAmB;AAU3D,MAAM,WAAW,MAAsB;AAC5C,QAAM,CAAC,YAAY,QAAQ,IAAI,SAAiB,EAAE,GAC5C,cAAc,OAA8C,IAAI,GAEhE,aAAa,YAAY,MAAM;AACnC,IAAI,YAAY,YACd,cAAc,YAAY,OAAO,GACjC,YAAY,UAAU;AAAA,EAE1B,GAAG,CAAC,CAAC,GAEC,aAAa;AAAA,IACjB,CAAC,MAAc,UAAmB;AAChC,eAAS,IAAI,GACb,WAAW,GACP,UACF,YAAY,UAAU,YAAY,MAAM;AACtC,iBAAS,CAAC,mBACJ,kBAAkB,KACpB,cAAc,YAAY,OAAQ,GAClC,YAAY,UAAU,MACf,KAEF,iBAAiB,CACzB;AAAA,MACH,GAAG,GAAI;AAAA,IAEX;AAAA,IACA,CAAC,UAAU;AAAA,EACb,GAEM,aAAa,YAAY,MAAM;AACnC,eAAW;AAAA,EACb,GAAG,CAAC,UAAU,CAAC,GAET,cAAc,YAAY,MAAM;AACpC,IAAK,YAAY,YACf,YAAY,UAAU,YAAY,MAAM;AACtC,eAAS,CAAC,mBACJ,kBAAkB,KACpB,cAAc,YAAY,OAAQ,GAClC,YAAY,UAAU,MACf,KAEF,iBAAiB,CACzB;AAAA,IACH,GAAG,GAAI;AAAA,EAEX,GAAG,CAAC,CAAC;AAEL,mBAAU,MACD,MAAM;AACX,IAAI,YAAY,YACd,cAAc,YAAY,OAAO,GACjC,YAAY,UAAU;AAAA,EAE1B,GACC,CAAC,CAAC,GAEE;AAAA,IACL,OAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,IACA,CAAC,YAAY,YAAY,YAAY,YAAY,WAAW;AAAA,EAC9D;AACF;",
5
+ "names": []
6
+ }
@@ -0,0 +1,32 @@
1
+ import { useState, useEffect, useRef, useMemo, useCallback } from "react";
2
+ const useTimer = () => {
3
+ const [timerCount, setTimer] = useState(30),
4
+ intervalRef = useRef(null),
5
+ clearTimer = useCallback(() => {
6
+ intervalRef.current && (clearInterval(intervalRef.current), intervalRef.current = null);
7
+ }, []),
8
+ resetTimer = useCallback((time, start) => {
9
+ setTimer(time), clearTimer(), start && (intervalRef.current = setInterval(() => {
10
+ setTimer(lastTimerCount => lastTimerCount <= 1 ? (clearInterval(intervalRef.current), intervalRef.current = null, 0) : lastTimerCount - 1);
11
+ }, 1e3));
12
+ }, [clearTimer]),
13
+ pauseTimer = useCallback(() => {
14
+ clearTimer();
15
+ }, [clearTimer]),
16
+ resumeTimer = useCallback(() => {
17
+ intervalRef.current || (intervalRef.current = setInterval(() => {
18
+ setTimer(lastTimerCount => lastTimerCount <= 1 ? (clearInterval(intervalRef.current), intervalRef.current = null, 0) : lastTimerCount - 1);
19
+ }, 1e3));
20
+ }, []);
21
+ return useEffect(() => () => {
22
+ intervalRef.current && (clearInterval(intervalRef.current), intervalRef.current = null);
23
+ }, []), useMemo(() => ({
24
+ count: timerCount,
25
+ start: resetTimer,
26
+ pause: pauseTimer,
27
+ resume: resumeTimer,
28
+ clear: clearTimer
29
+ }), [timerCount, clearTimer, pauseTimer, resetTimer, resumeTimer]);
30
+ };
31
+ export { useTimer };
32
+ //# sourceMappingURL=useTimer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useState","useEffect","useRef","useMemo","useCallback","useTimer","timerCount","setTimer","intervalRef","clearTimer","current","clearInterval","resetTimer","time","start","setInterval","lastTimerCount","pauseTimer","resumeTimer","count","pause","resume","clear"],"sources":["../../../src/time/useTimer.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,QAAA,EAAUC,SAAA,EAAWC,MAAA,EAAQC,OAAA,EAASC,WAAA,QAAmB;AAU3D,MAAMC,QAAA,GAAWA,CAAA,KAAsB;EAC5C,MAAM,CAACC,UAAA,EAAYC,QAAQ,IAAIP,QAAA,CAAiB,EAAE;IAC5CQ,WAAA,GAAcN,MAAA,CAA8C,IAAI;IAEhEO,UAAA,GAAaL,WAAA,CAAY,MAAM;MAC/BI,WAAA,CAAYE,OAAA,KACdC,aAAA,CAAcH,WAAA,CAAYE,OAAO,GACjCF,WAAA,CAAYE,OAAA,GAAU;IAE1B,GAAG,EAAE;IAECE,UAAA,GAAaR,WAAA,CACjB,CAACS,IAAA,EAAcC,KAAA,KAAmB;MAChCP,QAAA,CAASM,IAAI,GACbJ,UAAA,CAAW,GACPK,KAAA,KACFN,WAAA,CAAYE,OAAA,GAAUK,WAAA,CAAY,MAAM;QACtCR,QAAA,CAAUS,cAAA,IACJA,cAAA,IAAkB,KACpBL,aAAA,CAAcH,WAAA,CAAYE,OAAQ,GAClCF,WAAA,CAAYE,OAAA,GAAU,MACf,KAEFM,cAAA,GAAiB,CACzB;MACH,GAAG,GAAI;IAEX,GACA,CAACP,UAAU,CACb;IAEMQ,UAAA,GAAab,WAAA,CAAY,MAAM;MACnCK,UAAA,CAAW;IACb,GAAG,CAACA,UAAU,CAAC;IAETS,WAAA,GAAcd,WAAA,CAAY,MAAM;MAC/BI,WAAA,CAAYE,OAAA,KACfF,WAAA,CAAYE,OAAA,GAAUK,WAAA,CAAY,MAAM;QACtCR,QAAA,CAAUS,cAAA,IACJA,cAAA,IAAkB,KACpBL,aAAA,CAAcH,WAAA,CAAYE,OAAQ,GAClCF,WAAA,CAAYE,OAAA,GAAU,MACf,KAEFM,cAAA,GAAiB,CACzB;MACH,GAAG,GAAI;IAEX,GAAG,EAAE;EAEL,OAAAf,SAAA,CAAU,MACD,MAAM;IACPO,WAAA,CAAYE,OAAA,KACdC,aAAA,CAAcH,WAAA,CAAYE,OAAO,GACjCF,WAAA,CAAYE,OAAA,GAAU;EAE1B,GACC,EAAE,GAEEP,OAAA,CACL,OAAO;IACLgB,KAAA,EAAOb,UAAA;IACPQ,KAAA,EAAOF,UAAA;IACPQ,KAAA,EAAOH,UAAA;IACPI,MAAA,EAAQH,WAAA;IACRI,KAAA,EAAOb;EACT,IACA,CAACH,UAAA,EAAYG,UAAA,EAAYQ,UAAA,EAAYL,UAAA,EAAYM,WAAW,CAC9D;AACF","ignoreList":[]}
@@ -0,0 +1,40 @@
1
+ import { useState, useEffect, useRef, useMemo, useCallback } from "react";
2
+ var useTimer = function () {
3
+ var [timerCount, setTimer] = useState(30),
4
+ intervalRef = useRef(null),
5
+ clearTimer = useCallback(function () {
6
+ intervalRef.current && (clearInterval(intervalRef.current), intervalRef.current = null);
7
+ }, []),
8
+ resetTimer = useCallback(function (time, start) {
9
+ setTimer(time), clearTimer(), start && (intervalRef.current = setInterval(function () {
10
+ setTimer(function (lastTimerCount) {
11
+ return lastTimerCount <= 1 ? (clearInterval(intervalRef.current), intervalRef.current = null, 0) : lastTimerCount - 1;
12
+ });
13
+ }, 1e3));
14
+ }, [clearTimer]),
15
+ pauseTimer = useCallback(function () {
16
+ clearTimer();
17
+ }, [clearTimer]),
18
+ resumeTimer = useCallback(function () {
19
+ intervalRef.current || (intervalRef.current = setInterval(function () {
20
+ setTimer(function (lastTimerCount) {
21
+ return lastTimerCount <= 1 ? (clearInterval(intervalRef.current), intervalRef.current = null, 0) : lastTimerCount - 1;
22
+ });
23
+ }, 1e3));
24
+ }, []);
25
+ return useEffect(function () {
26
+ return function () {
27
+ intervalRef.current && (clearInterval(intervalRef.current), intervalRef.current = null);
28
+ };
29
+ }, []), useMemo(function () {
30
+ return {
31
+ count: timerCount,
32
+ start: resetTimer,
33
+ pause: pauseTimer,
34
+ resume: resumeTimer,
35
+ clear: clearTimer
36
+ };
37
+ }, [timerCount, clearTimer, pauseTimer, resetTimer, resumeTimer]);
38
+ };
39
+ export { useTimer };
40
+ //# sourceMappingURL=useTimer.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useState","useEffect","useRef","useMemo","useCallback","useTimer","timerCount","setTimer","intervalRef","clearTimer","current","clearInterval","resetTimer","time","start","setInterval","lastTimerCount","pauseTimer","resumeTimer","count"],"sources":["../../../src/time/useTimer.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,QAAA,EAAUC,SAAA,EAAWC,MAAA,EAAQC,OAAA,EAASC,WAAA,QAAmB;AAU3D,IAAAC,QAAM,YAAAA,CAAA,EAAiC;EAC5C,KAAAC,UAAO,EAAAC,QAAY,IAAQP,QAAI,GAAiB;IAAEQ,WAC5C,GAAAN,MAAc,KAA8C;IAAIO,UAEhE,GAAAL,WAAa,aAAkB;MAC/BI,WAAA,CAAYE,OAAA,KACdC,aAAA,CAAcH,WAAA,CAAYE,OAAO,GACjCF,WAAA,CAAYE,OAAA,GAAU;IAE1B,GAAG,EAAE;IAECE,UAAA,GAAaR,WAAA,WAAAS,IAAA,EAAAC,KAAA;MACjBP,QAAe,CAAAM,IAAA,GAAAJ,UAAmB,IAAAK,KAAA,KAAAN,WAAA,CAAAE,OAAA,GAAAK,WAAA;QAChCR,QAAA,CAAS,UACTS,cACI;UAEA,OAAAA,cAAU,SACJL,aAAA,CAAAH,WACF,CAAAE,OAAA,GAAcF,WAAA,CAAYE,OAAQ,GAClC,WAAAM,cAAsB,GACf;QAIb;MAEJ;IAAA,GACC,CACHP,UAEM,CACJ;IAAAQ,UAAW,GAAAb,WAAA;MACbK,UAAI,EAAU;IAGZ,GAAK,CAEDA,UAAA,CAOC,CACH;IAAAS,WAAO,GAAAd,WAAA;MAEXI,WAAK,CAAAE,OAAA,KAAAF,WAAA,CAAAE,OAAA,GAAAK,WAAA;QAELR,QAAA,WAAUS,cACK;UACP,OAAAA,cACF,SAAAL,aAAc,CAAAH,WAAmB,CACjCE,OAAA,GAAAF,WAAY,CAAUE,OAAA,cAAAM,cAAA;QAGxB,CAAC;MAGH,OAAO;IAAA,KACL;EAAO,OACPf,SAAO;IAAA,OACP,YAAO;MACPO,WAAQ,CAAAE,OAAA,KAAAC,aAAA,CAAAH,WAAA,CAAAE,OAAA,GAAAF,WAAA,CAAAE,OAAA;IAAA;EACD,GACT,KAAAP,OAAA;IACA,OAAC;MACHgB,KAAA,EAAAb,UAAA;MACFQ,KAAA,EAAAF,UAAA","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@take-out/helpers",
3
- "version": "0.0.40",
3
+ "version": "0.0.42",
4
4
  "sideEffects": false,
5
5
  "type": "module",
6
6
  "source": "src/index.ts",
@@ -60,6 +60,7 @@
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@rocicorp/zero": "*",
63
+ "expo-clipboard": "*",
63
64
  "react": "*",
64
65
  "react-native": "*"
65
66
  },
@@ -14,10 +14,13 @@ interface AsyncLocalStorageConstructor {
14
14
 
15
15
  let nodeAsyncLocalStorageCache: AsyncLocalStorageConstructor | null = null
16
16
 
17
+ // hide from vite/esbuild static analysis to avoid browser compat warning
18
+ const nodeModuleId = ['node', 'async_hooks'].join(':')
19
+
17
20
  async function getNodeAsyncLocalStorage(): Promise<AsyncLocalStorageConstructor | null> {
18
21
  if (!nodeAsyncLocalStorageCache) {
19
22
  try {
20
- const module = await import('node:async_hooks')
23
+ const module = await import(/* @vite-ignore */ nodeModuleId)
21
24
  nodeAsyncLocalStorageCache =
22
25
  module.AsyncLocalStorage as AsyncLocalStorageConstructor
23
26
  } catch {
@@ -0,0 +1,10 @@
1
+ import * as Clipboard from 'expo-clipboard'
2
+
3
+ export const getClipboardText = async (): Promise<string | null> => {
4
+ try {
5
+ const text = await Clipboard.getStringAsync()
6
+ return text
7
+ } catch {
8
+ return null
9
+ }
10
+ }
@@ -0,0 +1,8 @@
1
+ export const getClipboardText = async (): Promise<string | null> => {
2
+ try {
3
+ const text = await navigator.clipboard.readText()
4
+ return text
5
+ } catch {
6
+ return null
7
+ }
8
+ }
@@ -0,0 +1,18 @@
1
+ export function extractOpacityFromColor(color: string): number {
2
+ if (color === 'transparent') return 0
3
+
4
+ // Match hex codes like #RRGGBBAA or #RRGGBB
5
+ const hexMatch = color.match(/^#([0-9a-fA-F]{6})([0-9a-fA-F]{2})?$/)
6
+ if (hexMatch) {
7
+ const [, _rgb, alphaHex] = hexMatch
8
+ if (alphaHex) {
9
+ const alpha = parseInt(alphaHex, 16)
10
+ return alpha / 255
11
+ }
12
+ return 1 // No alpha specified → fully opaque
13
+ }
14
+
15
+ // Could expand this to support rgba(), hsl(), etc. if needed
16
+ console.warn(`Unsupported color format: ${color}`)
17
+ return 1
18
+ }
@@ -0,0 +1,72 @@
1
+ import { toHex } from './toHex'
2
+
3
+ type ColorGenOptions = {
4
+ numColors?: number
5
+ minSaturation?: number
6
+ maxSaturation?: number
7
+ minLightness?: number
8
+ maxLightness?: number
9
+ }
10
+
11
+ // convert HSL to hex
12
+ function hslToHex(h: number, s: number, l: number): string {
13
+ // normalize values
14
+ h = h / 360
15
+ s = s / 100
16
+ l = l / 100
17
+
18
+ const a = s * Math.min(l, 1 - l)
19
+ const f = (n: number) => {
20
+ const k = (n + h * 12) % 12
21
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1)
22
+ return Math.round(255 * color)
23
+ }
24
+
25
+ const r = f(0)
26
+ const g = f(8)
27
+ const b = f(4)
28
+
29
+ return toHex((r << 16) | (g << 8) | b)
30
+ }
31
+
32
+ export const generateColors = ({
33
+ numColors = 32,
34
+ minSaturation = 45,
35
+ maxSaturation = 85,
36
+ minLightness = 45,
37
+ maxLightness = 65,
38
+ }: ColorGenOptions = {}): string[] => {
39
+ const colors: string[] = []
40
+
41
+ // Define hue ranges for color groups
42
+ const hueRanges = [
43
+ [0, 30], // reds
44
+ [30, 60], // oranges
45
+ [60, 90], // yellows
46
+ [90, 150], // greens
47
+ [150, 180], // teals
48
+ [180, 240], // blues
49
+ [240, 270], // purples
50
+ [270, 330], // magentas
51
+ [330, 360], // pink-reds
52
+ ]
53
+
54
+ // Calculate colors per group
55
+ const colorsPerGroup = Math.ceil(numColors / hueRanges.length)
56
+
57
+ hueRanges.forEach(([start, end]) => {
58
+ const hueStep = (end! - start!) / colorsPerGroup
59
+
60
+ for (let i = 0; i < colorsPerGroup; i++) {
61
+ if (colors.length >= numColors) break
62
+
63
+ const hue = start! + hueStep * i
64
+ const saturation = minSaturation + Math.random() * (maxSaturation - minSaturation)
65
+ const lightness = minLightness + Math.random() * (maxLightness - minLightness)
66
+
67
+ colors.push(hslToHex(hue, saturation, lightness))
68
+ }
69
+ })
70
+
71
+ return colors
72
+ }
@@ -0,0 +1,78 @@
1
+ // Helper to ensure color string is valid (simple fallback implementation)
2
+ const validColor = (color: string) => color
3
+
4
+ export function lum(color: string, luminance = 0.5): string {
5
+ // handle hsl/hsla
6
+ if (color.startsWith('hsl')) {
7
+ const match = color.match(/hsla?\((\d+),\s*(\d+)%,\s*(\d+)%(?:,\s*([\d.]+))?\)/)
8
+ if (match) {
9
+ const [, h, s, , a] = match
10
+ const newL = Math.round(luminance * 100)
11
+ if (a) {
12
+ return validColor(`hsla(${h}, ${s}%, ${newL}%, ${a})`)
13
+ }
14
+ return validColor(`hsl(${h}, ${s}%, ${newL}%)`)
15
+ }
16
+ }
17
+
18
+ // handle hex - convert to hsl and adjust
19
+ if (color.startsWith('#')) {
20
+ let hex = color.slice(1)
21
+
22
+ // expand shorthand hex
23
+ if (hex.length === 3) {
24
+ hex = hex
25
+ .split('')
26
+ .map((c) => c + c)
27
+ .join('')
28
+ }
29
+
30
+ // convert hex to rgb
31
+ const r = parseInt(hex.slice(0, 2), 16) / 255
32
+ const g = parseInt(hex.slice(2, 4), 16) / 255
33
+ const b = parseInt(hex.slice(4, 6), 16) / 255
34
+
35
+ // convert rgb to hsl
36
+ const max = Math.max(r, g, b)
37
+ const min = Math.min(r, g, b)
38
+ const l = (max + min) / 2
39
+
40
+ if (max === min) {
41
+ // achromatic
42
+ const newL = Math.round(luminance * 100)
43
+ return validColor(`hsl(0, 0%, ${newL}%)`)
44
+ }
45
+
46
+ const d = max - min
47
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
48
+
49
+ let h: number
50
+ switch (max) {
51
+ case r:
52
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6
53
+ break
54
+ case g:
55
+ h = ((b - r) / d + 2) / 6
56
+ break
57
+ case b:
58
+ h = ((r - g) / d + 4) / 6
59
+ break
60
+ default:
61
+ h = 0
62
+ }
63
+
64
+ const newH = Math.round(h * 360)
65
+ const newS = Math.round(s * 100)
66
+ const newL = Math.round(luminance * 100)
67
+
68
+ // preserve alpha if present
69
+ if (hex.length === 8) {
70
+ const alpha = parseInt(hex.slice(6, 8), 16) / 255
71
+ return validColor(`hsla(${newH}, ${newS}%, ${newL}%, ${alpha.toFixed(2)})`)
72
+ }
73
+
74
+ return validColor(`hsl(${newH}, ${newS}%, ${newL}%)`)
75
+ }
76
+
77
+ return validColor(color)
78
+ }
@@ -0,0 +1,10 @@
1
+ // simple helper to ensure we always get a valid 6-digit hex color from a number
2
+ export function toHex(value: number): string {
3
+ // ensure we get a 6-digit hex string with leading zeros if needed
4
+ return '#' + value.toString(16).padStart(6, '0')
5
+ }
6
+
7
+ // generate a random hex color
8
+ export function randomHex(): string {
9
+ return toHex(Math.floor(Math.random() * 0xffffff))
10
+ }
package/src/index.ts CHANGED
@@ -23,6 +23,15 @@ export * from './async/useLazyValue'
23
23
 
24
24
  // browser
25
25
  export * from './browser/clearIndexedDB'
26
+
27
+ // clipboard
28
+ export * from './clipboard/clipboard'
29
+
30
+ // color
31
+ export * from './color/toHex'
32
+ export * from './color/generateColors'
33
+ export * from './color/lum'
34
+ export * from './color/extractOpacityFromColor'
26
35
  export * from './browser/isActiveElementFormField'
27
36
  export * from './browser/openPopup'
28
37
 
@@ -92,7 +101,9 @@ export * from './string/truncateList'
92
101
  // time
93
102
  export * from './time/formatDate'
94
103
  export * from './time/formatDateRelative'
104
+ export * from './time/formatDistanceToNow'
95
105
  export * from './time/time'
106
+ export * from './time/useTimer'
96
107
 
97
108
  // types
98
109
  export type * from './types/NullToOptional'
@@ -38,3 +38,18 @@ export function formatCount(value: number): string {
38
38
  forceCompact: value >= 1000,
39
39
  })
40
40
  }
41
+
42
+ export function formatReactionCount(value: number | string): string {
43
+ if (typeof value === 'string') return value
44
+ if (value >= 1000000) {
45
+ return `${(value / 1000000).toFixed(1)}M`
46
+ }
47
+ if (value >= 1000) {
48
+ return `${(value / 1000).toFixed(1)}K`
49
+ }
50
+ return value.toString()
51
+ }
52
+
53
+ export function formatPhoneNumber(value: string): string {
54
+ return value
55
+ }
@@ -0,0 +1,17 @@
1
+ export function formatDistanceToNow(timestamp: number): string {
2
+ const now = Date.now()
3
+ const diff = now - timestamp
4
+
5
+ const minutes = Math.floor(diff / 60000)
6
+ const hours = Math.floor(diff / 3600000)
7
+ const days = Math.floor(diff / 86400000)
8
+
9
+ if (minutes < 1) return 'just now'
10
+ if (minutes < 60) return `${minutes}m`
11
+ if (hours < 24) return `${hours}h`
12
+ if (days < 7) return `${days}d`
13
+ if (days < 30) return `${Math.floor(days / 7)}w`
14
+ if (days < 365) return `${Math.floor(days / 30)}mo`
15
+
16
+ return `${Math.floor(days / 365)}y`
17
+ }
@@ -0,0 +1,80 @@
1
+ import { useState, useEffect, useRef, useMemo, useCallback } from 'react'
2
+
3
+ type UseTimerReturn = {
4
+ count: number
5
+ start: (time: number, start: boolean) => void
6
+ pause: () => void
7
+ resume: () => void
8
+ clear: () => void
9
+ }
10
+
11
+ export const useTimer = (): UseTimerReturn => {
12
+ const [timerCount, setTimer] = useState<number>(30)
13
+ const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
14
+
15
+ const clearTimer = useCallback(() => {
16
+ if (intervalRef.current) {
17
+ clearInterval(intervalRef.current)
18
+ intervalRef.current = null
19
+ }
20
+ }, [])
21
+
22
+ const resetTimer = useCallback(
23
+ (time: number, start: boolean) => {
24
+ setTimer(time)
25
+ clearTimer()
26
+ if (start) {
27
+ intervalRef.current = setInterval(() => {
28
+ setTimer((lastTimerCount) => {
29
+ if (lastTimerCount <= 1) {
30
+ clearInterval(intervalRef.current!)
31
+ intervalRef.current = null
32
+ return 0
33
+ }
34
+ return lastTimerCount - 1
35
+ })
36
+ }, 1000)
37
+ }
38
+ },
39
+ [clearTimer]
40
+ )
41
+
42
+ const pauseTimer = useCallback(() => {
43
+ clearTimer()
44
+ }, [clearTimer])
45
+
46
+ const resumeTimer = useCallback(() => {
47
+ if (!intervalRef.current) {
48
+ intervalRef.current = setInterval(() => {
49
+ setTimer((lastTimerCount) => {
50
+ if (lastTimerCount <= 1) {
51
+ clearInterval(intervalRef.current!)
52
+ intervalRef.current = null
53
+ return 0
54
+ }
55
+ return lastTimerCount - 1
56
+ })
57
+ }, 1000)
58
+ }
59
+ }, [])
60
+
61
+ useEffect(() => {
62
+ return () => {
63
+ if (intervalRef.current) {
64
+ clearInterval(intervalRef.current)
65
+ intervalRef.current = null
66
+ }
67
+ }
68
+ }, [])
69
+
70
+ return useMemo(
71
+ () => ({
72
+ count: timerCount,
73
+ start: resetTimer,
74
+ pause: pauseTimer,
75
+ resume: resumeTimer,
76
+ clear: clearTimer,
77
+ }),
78
+ [timerCount, clearTimer, pauseTimer, resetTimer, resumeTimer]
79
+ )
80
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "mappings": "UAAU,aAAa,GAAG;CACxB,OAAO;CACP,IAAI,GAAGA,OAAO,GAAGC,UAAU,IAAI,QAAQ,KAAK,QAAQ;AACrD;AA0BD,OAAO,iBAAS,mBAAmB,MAAM,aAAa",
2
+ "mappings": "UAAU,aAAa,GAAG;CACxB,OAAO;CACP,IAAI,GAAGA,OAAO,GAAGC,UAAU,IAAI,QAAQ,KAAK,QAAQ;AACrD;AA6BD,OAAO,iBAAS,mBAAmB,MAAM,aAAa",
3
3
  "names": [
4
4
  "value: T",
5
5
  "fn: () => R | Promise<R>"
@@ -8,7 +8,7 @@
8
8
  "src/async/asyncContext.ts"
9
9
  ],
10
10
  "sourcesContent": [
11
- "interface AsyncContext<T> {\n get(): T | undefined\n run<R>(value: T, fn: () => R | Promise<R>): Promise<R>\n}\n\ninterface NodeAsyncLocalStorage<T> {\n getStore(): T | undefined\n run<R>(store: T, callback: () => R): R\n}\n\ninterface AsyncLocalStorageConstructor {\n new <T>(): NodeAsyncLocalStorage<T>\n}\n\nlet nodeAsyncLocalStorageCache: AsyncLocalStorageConstructor | null = null\n\nasync function getNodeAsyncLocalStorage(): Promise<AsyncLocalStorageConstructor | null> {\n if (!nodeAsyncLocalStorageCache) {\n try {\n const module = await import('node:async_hooks')\n nodeAsyncLocalStorageCache =\n module.AsyncLocalStorage as AsyncLocalStorageConstructor\n } catch {\n return null\n }\n }\n return nodeAsyncLocalStorageCache\n}\n\nexport function createAsyncContext<T>(): AsyncContext<T> {\n if (process.env.VITE_ENVIRONMENT === 'ssr') {\n let storage: NodeAsyncLocalStorage<T> | null = null\n\n getNodeAsyncLocalStorage().then((AsyncLocalStorage) => {\n if (AsyncLocalStorage && !storage) {\n storage = new AsyncLocalStorage<T>()\n }\n })\n\n return {\n get(): T | undefined {\n if (!storage) {\n console.warn(`⚠️ called AsyncContext before load!`)\n return\n }\n\n return storage.getStore()\n },\n\n async run<R>(value: T, fn: () => R | Promise<R>): Promise<R> {\n if (!storage) {\n throw new Error(`⚠️ called AsyncContext before load!`)\n }\n return storage.run(value, fn)\n },\n }\n } else {\n // browser implementation using promise patching\n return createBrowserAsyncContext<T>()\n }\n}\n\nfunction createBrowserAsyncContext<T>(): AsyncContext<T> {\n let currentContext: T | undefined\n const contextStack: (T | undefined)[] = []\n\n return {\n get(): T | undefined {\n return currentContext\n },\n async run<R>(value: T, fn: () => R | Promise<R>): Promise<R> {\n const prevContext = currentContext\n currentContext = value\n contextStack.push(prevContext)\n\n // store original Promise methods\n const OriginalPromise = Promise\n const OriginalThen = OriginalPromise.prototype.then\n const OriginalCatch = OriginalPromise.prototype.catch\n const OriginalFinally = OriginalPromise.prototype.finally\n\n function wrapCallback(\n callback: Function | undefined | null,\n context: T | undefined\n ): Function | undefined | null {\n if (!callback) return callback\n return (...args: any[]) => {\n const prevContext = currentContext\n currentContext = context\n try {\n return callback(...args)\n } finally {\n currentContext = prevContext\n }\n }\n }\n\n // patch Promise methods to capture and restore context\n // eslint-disable-next-line no-then-property -- intentional patching for context propagation\n OriginalPromise.prototype.then = function (\n this: Promise<any>,\n onFulfilled?: any,\n onRejected?: any\n ): Promise<any> {\n const context = currentContext\n return OriginalThen.call(\n this,\n wrapCallback(onFulfilled, context) as any,\n wrapCallback(onRejected, context) as any\n )\n }\n\n OriginalPromise.prototype.catch = function (\n this: Promise<any>,\n onRejected?: any\n ): Promise<any> {\n const context = currentContext\n return OriginalCatch.call(this, wrapCallback(onRejected, context) as any)\n }\n\n OriginalPromise.prototype.finally = function (\n this: Promise<any>,\n onFinally?: any\n ): Promise<any> {\n const context = currentContext\n return OriginalFinally.call(this, wrapCallback(onFinally, context) as any)\n }\n\n try {\n const result = await fn()\n return result\n } finally {\n // restore original Promise methods\n // eslint-disable-next-line no-then-property -- restoring original methods\n OriginalPromise.prototype.then = OriginalThen\n OriginalPromise.prototype.catch = OriginalCatch\n OriginalPromise.prototype.finally = OriginalFinally\n\n contextStack.pop()\n currentContext = prevContext\n }\n },\n }\n}\n"
11
+ "interface AsyncContext<T> {\n get(): T | undefined\n run<R>(value: T, fn: () => R | Promise<R>): Promise<R>\n}\n\ninterface NodeAsyncLocalStorage<T> {\n getStore(): T | undefined\n run<R>(store: T, callback: () => R): R\n}\n\ninterface AsyncLocalStorageConstructor {\n new <T>(): NodeAsyncLocalStorage<T>\n}\n\nlet nodeAsyncLocalStorageCache: AsyncLocalStorageConstructor | null = null\n\n// hide from vite/esbuild static analysis to avoid browser compat warning\nconst nodeModuleId = ['node', 'async_hooks'].join(':')\n\nasync function getNodeAsyncLocalStorage(): Promise<AsyncLocalStorageConstructor | null> {\n if (!nodeAsyncLocalStorageCache) {\n try {\n const module = await import(/* @vite-ignore */ nodeModuleId)\n nodeAsyncLocalStorageCache =\n module.AsyncLocalStorage as AsyncLocalStorageConstructor\n } catch {\n return null\n }\n }\n return nodeAsyncLocalStorageCache\n}\n\nexport function createAsyncContext<T>(): AsyncContext<T> {\n if (process.env.VITE_ENVIRONMENT === 'ssr') {\n let storage: NodeAsyncLocalStorage<T> | null = null\n\n getNodeAsyncLocalStorage().then((AsyncLocalStorage) => {\n if (AsyncLocalStorage && !storage) {\n storage = new AsyncLocalStorage<T>()\n }\n })\n\n return {\n get(): T | undefined {\n if (!storage) {\n console.warn(`⚠️ called AsyncContext before load!`)\n return\n }\n\n return storage.getStore()\n },\n\n async run<R>(value: T, fn: () => R | Promise<R>): Promise<R> {\n if (!storage) {\n throw new Error(`⚠️ called AsyncContext before load!`)\n }\n return storage.run(value, fn)\n },\n }\n } else {\n // browser implementation using promise patching\n return createBrowserAsyncContext<T>()\n }\n}\n\nfunction createBrowserAsyncContext<T>(): AsyncContext<T> {\n let currentContext: T | undefined\n const contextStack: (T | undefined)[] = []\n\n return {\n get(): T | undefined {\n return currentContext\n },\n async run<R>(value: T, fn: () => R | Promise<R>): Promise<R> {\n const prevContext = currentContext\n currentContext = value\n contextStack.push(prevContext)\n\n // store original Promise methods\n const OriginalPromise = Promise\n const OriginalThen = OriginalPromise.prototype.then\n const OriginalCatch = OriginalPromise.prototype.catch\n const OriginalFinally = OriginalPromise.prototype.finally\n\n function wrapCallback(\n callback: Function | undefined | null,\n context: T | undefined\n ): Function | undefined | null {\n if (!callback) return callback\n return (...args: any[]) => {\n const prevContext = currentContext\n currentContext = context\n try {\n return callback(...args)\n } finally {\n currentContext = prevContext\n }\n }\n }\n\n // patch Promise methods to capture and restore context\n // eslint-disable-next-line no-then-property -- intentional patching for context propagation\n OriginalPromise.prototype.then = function (\n this: Promise<any>,\n onFulfilled?: any,\n onRejected?: any\n ): Promise<any> {\n const context = currentContext\n return OriginalThen.call(\n this,\n wrapCallback(onFulfilled, context) as any,\n wrapCallback(onRejected, context) as any\n )\n }\n\n OriginalPromise.prototype.catch = function (\n this: Promise<any>,\n onRejected?: any\n ): Promise<any> {\n const context = currentContext\n return OriginalCatch.call(this, wrapCallback(onRejected, context) as any)\n }\n\n OriginalPromise.prototype.finally = function (\n this: Promise<any>,\n onFinally?: any\n ): Promise<any> {\n const context = currentContext\n return OriginalFinally.call(this, wrapCallback(onFinally, context) as any)\n }\n\n try {\n const result = await fn()\n return result\n } finally {\n // restore original Promise methods\n // eslint-disable-next-line no-then-property -- restoring original methods\n OriginalPromise.prototype.then = OriginalThen\n OriginalPromise.prototype.catch = OriginalCatch\n OriginalPromise.prototype.finally = OriginalFinally\n\n contextStack.pop()\n currentContext = prevContext\n }\n },\n }\n}\n"
12
12
  ],
13
13
  "version": 3
14
14
  }
@@ -0,0 +1,9 @@
1
+ // browser/native implementation - no node:async_hooks
2
+ interface AsyncContext<T> {
3
+ get(): T | undefined;
4
+ run<R>(value: T, fn: () => R | Promise<R>): Promise<R>;
5
+ }
6
+ export declare function createAsyncContext<T>(): AsyncContext<T>;
7
+ export {};
8
+
9
+ //# sourceMappingURL=asyncContext.native.d.ts.map
@@ -0,0 +1,14 @@
1
+ {
2
+ "mappings": ";UAEU,aAAa,GAAG;CACxB,OAAO;CACP,IAAI,GAAGA,OAAO,GAAGC,UAAU,IAAI,QAAQ,KAAK,QAAQ;AACrD;AAED,OAAO,iBAAS,mBAAmB,MAAM,aAAa",
3
+ "names": [
4
+ "value: T",
5
+ "fn: () => R | Promise<R>"
6
+ ],
7
+ "sources": [
8
+ "src/async/asyncContext.native.ts"
9
+ ],
10
+ "sourcesContent": [
11
+ "// browser/native implementation - no node:async_hooks\n\ninterface AsyncContext<T> {\n get(): T | undefined\n run<R>(value: T, fn: () => R | Promise<R>): Promise<R>\n}\n\nexport function createAsyncContext<T>(): AsyncContext<T> {\n let currentContext: T | undefined\n const contextStack: (T | undefined)[] = []\n\n return {\n get(): T | undefined {\n return currentContext\n },\n async run<R>(value: T, fn: () => R | Promise<R>): Promise<R> {\n const prevContext = currentContext\n currentContext = value\n contextStack.push(prevContext)\n\n // store original Promise methods\n const OriginalPromise = Promise\n const OriginalThen = OriginalPromise.prototype.then\n const OriginalCatch = OriginalPromise.prototype.catch\n const OriginalFinally = OriginalPromise.prototype.finally\n\n function wrapCallback(\n callback: Function | undefined | null,\n context: T | undefined\n ): Function | undefined | null {\n if (!callback) return callback\n return (...args: any[]) => {\n const prevContext = currentContext\n currentContext = context\n try {\n return callback(...args)\n } finally {\n currentContext = prevContext\n }\n }\n }\n\n // patch Promise methods to capture and restore context\n // eslint-disable-next-line no-then-property -- intentional patching for context propagation\n OriginalPromise.prototype.then = function (\n this: Promise<any>,\n onFulfilled?: any,\n onRejected?: any\n ): Promise<any> {\n const context = currentContext\n return OriginalThen.call(\n this,\n wrapCallback(onFulfilled, context) as any,\n wrapCallback(onRejected, context) as any\n )\n }\n\n OriginalPromise.prototype.catch = function (\n this: Promise<any>,\n onRejected?: any\n ): Promise<any> {\n const context = currentContext\n return OriginalCatch.call(this, wrapCallback(onRejected, context) as any)\n }\n\n OriginalPromise.prototype.finally = function (\n this: Promise<any>,\n onFinally?: any\n ): Promise<any> {\n const context = currentContext\n return OriginalFinally.call(this, wrapCallback(onFinally, context) as any)\n }\n\n try {\n const result = await fn()\n return result\n } finally {\n // restore original Promise methods\n // eslint-disable-next-line no-then-property -- restoring original methods\n OriginalPromise.prototype.then = OriginalThen\n OriginalPromise.prototype.catch = OriginalCatch\n OriginalPromise.prototype.finally = OriginalFinally\n\n contextStack.pop()\n currentContext = prevContext\n }\n },\n }\n}\n"
12
+ ],
13
+ "version": 3
14
+ }
@@ -0,0 +1,3 @@
1
+ export declare const getClipboardText: () => Promise<string | null>;
2
+
3
+ //# sourceMappingURL=clipboard.d.ts.map