minimal-shared 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. package/README.md +3 -0
  2. package/dist/hooks/index.d.ts +20 -0
  3. package/dist/hooks/index.js +19 -0
  4. package/dist/hooks/use-back-to-top/index.d.ts +2 -0
  5. package/dist/hooks/use-back-to-top/index.js +1 -0
  6. package/dist/hooks/use-back-to-top/use-back-to-top.d.ts +33 -0
  7. package/dist/hooks/use-back-to-top/use-back-to-top.js +64 -0
  8. package/dist/hooks/use-boolean/index.d.ts +2 -0
  9. package/dist/hooks/use-boolean/index.js +1 -0
  10. package/dist/hooks/use-boolean/use-boolean.d.ts +29 -0
  11. package/dist/hooks/use-boolean/use-boolean.js +24 -0
  12. package/dist/hooks/use-client-rect/index.d.ts +2 -0
  13. package/dist/hooks/use-client-rect/index.js +1 -0
  14. package/dist/hooks/use-client-rect/use-client-rect.d.ts +29 -0
  15. package/dist/hooks/use-client-rect/use-client-rect.js +47 -0
  16. package/dist/hooks/use-cookies/index.d.ts +1 -0
  17. package/dist/hooks/use-cookies/index.js +1 -0
  18. package/dist/hooks/use-cookies/use-cookies.d.ts +39 -0
  19. package/dist/hooks/use-cookies/use-cookies.js +110 -0
  20. package/dist/hooks/use-copy-to-clipboard/index.d.ts +1 -0
  21. package/dist/hooks/use-copy-to-clipboard/index.js +1 -0
  22. package/dist/hooks/use-copy-to-clipboard/use-copy-to-clipboard.d.ts +26 -0
  23. package/dist/hooks/use-copy-to-clipboard/use-copy-to-clipboard.js +27 -0
  24. package/dist/hooks/use-countdown-date/index.d.ts +1 -0
  25. package/dist/hooks/use-countdown-date/index.js +1 -0
  26. package/dist/hooks/use-countdown-date/use-countdown-date.d.ts +29 -0
  27. package/dist/hooks/use-countdown-date/use-countdown-date.js +41 -0
  28. package/dist/hooks/use-countdown-seconds/index.d.ts +2 -0
  29. package/dist/hooks/use-countdown-seconds/index.js +1 -0
  30. package/dist/hooks/use-countdown-seconds/use-countdown-seconds.d.ts +35 -0
  31. package/dist/hooks/use-countdown-seconds/use-countdown-seconds.js +36 -0
  32. package/dist/hooks/use-debounce/index.d.ts +1 -0
  33. package/dist/hooks/use-debounce/index.js +1 -0
  34. package/dist/hooks/use-debounce/use-debounce.d.ts +21 -0
  35. package/dist/hooks/use-debounce/use-debounce.js +17 -0
  36. package/dist/hooks/use-double-click/index.d.ts +2 -0
  37. package/dist/hooks/use-double-click/index.js +1 -0
  38. package/dist/hooks/use-double-click/use-double-click.d.ts +28 -0
  39. package/dist/hooks/use-double-click/use-double-click.js +33 -0
  40. package/dist/hooks/use-event-listener/index.d.ts +2 -0
  41. package/dist/hooks/use-event-listener/index.js +1 -0
  42. package/dist/hooks/use-event-listener/use-event-listener.d.ts +7 -0
  43. package/dist/hooks/use-event-listener/use-event-listener.js +23 -0
  44. package/dist/hooks/use-is-client/index.d.ts +1 -0
  45. package/dist/hooks/use-is-client/index.js +1 -0
  46. package/dist/hooks/use-is-client/use-is-client.d.ts +18 -0
  47. package/dist/hooks/use-is-client/use-is-client.js +12 -0
  48. package/dist/hooks/use-local-storage/index.d.ts +1 -0
  49. package/dist/hooks/use-local-storage/index.js +1 -0
  50. package/dist/hooks/use-local-storage/use-local-storage.d.ts +37 -0
  51. package/dist/hooks/use-local-storage/use-local-storage.js +113 -0
  52. package/dist/hooks/use-multi-select/index.d.ts +2 -0
  53. package/dist/hooks/use-multi-select/index.js +1 -0
  54. package/dist/hooks/use-multi-select/use-multi-select.d.ts +55 -0
  55. package/dist/hooks/use-multi-select/use-multi-select.js +36 -0
  56. package/dist/hooks/use-popover/index.d.ts +2 -0
  57. package/dist/hooks/use-popover/index.js +1 -0
  58. package/dist/hooks/use-popover/use-popover.d.ts +35 -0
  59. package/dist/hooks/use-popover/use-popover.js +21 -0
  60. package/dist/hooks/use-popover-hover/index.d.ts +2 -0
  61. package/dist/hooks/use-popover-hover/index.js +1 -0
  62. package/dist/hooks/use-popover-hover/use-popover-hover.d.ts +41 -0
  63. package/dist/hooks/use-popover-hover/use-popover-hover.js +24 -0
  64. package/dist/hooks/use-scroll-offset-top/index.d.ts +2 -0
  65. package/dist/hooks/use-scroll-offset-top/index.js +1 -0
  66. package/dist/hooks/use-scroll-offset-top/use-scroll-offset-top.d.ts +28 -0
  67. package/dist/hooks/use-scroll-offset-top/use-scroll-offset-top.js +29 -0
  68. package/dist/hooks/use-set-state/index.d.ts +1 -0
  69. package/dist/hooks/use-set-state/index.js +1 -0
  70. package/dist/hooks/use-set-state/use-set-state.d.ts +32 -0
  71. package/dist/hooks/use-set-state/use-set-state.js +26 -0
  72. package/dist/hooks/use-tabs/index.d.ts +2 -0
  73. package/dist/hooks/use-tabs/index.js +1 -0
  74. package/dist/hooks/use-tabs/use-tabs.d.ts +30 -0
  75. package/dist/hooks/use-tabs/use-tabs.js +16 -0
  76. package/dist/hooks/use-text-input/index.d.ts +2 -0
  77. package/dist/hooks/use-text-input/index.js +1 -0
  78. package/dist/hooks/use-text-input/use-text-input.d.ts +16 -0
  79. package/dist/hooks/use-text-input/use-text-input.js +16 -0
  80. package/dist/index.d.ts +29 -0
  81. package/dist/index.js +2 -0
  82. package/dist/utils/active-link/active-link.d.ts +16 -0
  83. package/dist/utils/active-link/active-link.js +43 -0
  84. package/dist/utils/active-link/index.d.ts +1 -0
  85. package/dist/utils/active-link/index.js +1 -0
  86. package/dist/utils/classes/classes.d.ts +25 -0
  87. package/dist/utils/classes/classes.js +14 -0
  88. package/dist/utils/classes/index.d.ts +1 -0
  89. package/dist/utils/classes/index.js +1 -0
  90. package/dist/utils/color/color.d.ts +67 -0
  91. package/dist/utils/color/color.js +47 -0
  92. package/dist/utils/color/index.d.ts +1 -0
  93. package/dist/utils/color/index.js +1 -0
  94. package/dist/utils/cookies/cookies.d.ts +34 -0
  95. package/dist/utils/cookies/cookies.js +46 -0
  96. package/dist/utils/cookies/index.d.ts +1 -0
  97. package/dist/utils/cookies/index.js +1 -0
  98. package/dist/utils/font/font.d.ts +37 -0
  99. package/dist/utils/font/font.js +20 -0
  100. package/dist/utils/font/index.d.ts +1 -0
  101. package/dist/utils/font/index.js +1 -0
  102. package/dist/utils/index.d.ts +9 -0
  103. package/dist/utils/index.js +17 -0
  104. package/dist/utils/local-storage/index.d.ts +1 -0
  105. package/dist/utils/local-storage/index.js +1 -0
  106. package/dist/utils/local-storage/local-storage.d.ts +55 -0
  107. package/dist/utils/local-storage/local-storage.js +51 -0
  108. package/dist/utils/object/index.d.ts +1 -0
  109. package/dist/utils/object/index.js +1 -0
  110. package/dist/utils/object/object.d.ts +26 -0
  111. package/dist/utils/object/object.js +10 -0
  112. package/dist/utils/url/index.d.ts +1 -0
  113. package/dist/utils/url/index.js +1 -0
  114. package/dist/utils/url/url.d.ts +46 -0
  115. package/dist/utils/url/url.js +28 -0
  116. package/dist/utils/uuidv4/index.d.ts +1 -0
  117. package/dist/utils/uuidv4/index.js +1 -0
  118. package/dist/utils/uuidv4/uuidv4.d.ts +12 -0
  119. package/dist/utils/uuidv4/uuidv4.js +11 -0
  120. package/package.json +87 -0
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @minimals shared
2
+
3
+ Shared hooks and utils used by Mnimal UI and Zone UI.
@@ -0,0 +1,20 @@
1
+ export { UseTabsReturn, useTabs } from './use-tabs/use-tabs.js';
2
+ export { UseBooleanReturn, useBoolean } from './use-boolean/use-boolean.js';
3
+ export { UsePopoverReturn, usePopover } from './use-popover/use-popover.js';
4
+ export { UseCookiesReturn, useCookies } from './use-cookies/use-cookies.js';
5
+ export { UseDebounceReturn, useDebounce } from './use-debounce/use-debounce.js';
6
+ export { UseSetStateReturn, useSetState } from './use-set-state/use-set-state.js';
7
+ export { UseIsClientReturn, useIsClient } from './use-is-client/use-is-client.js';
8
+ export { UseTextInputReturn, useTextInput } from './use-text-input/use-text-input.js';
9
+ export { UseBackToTopReturn, useBackToTop } from './use-back-to-top/use-back-to-top.js';
10
+ export { UseClientRectReturn, useClientRect } from './use-client-rect/use-client-rect.js';
11
+ export { UseMultiSelectReturn, updateSelectedItems, useMultiSelect } from './use-multi-select/use-multi-select.js';
12
+ export { UseDoubleClickReturn, useDoubleClick } from './use-double-click/use-double-click.js';
13
+ export { UseLocalStorageReturn, useLocalStorage } from './use-local-storage/use-local-storage.js';
14
+ export { usePopoverHover } from './use-popover-hover/use-popover-hover.js';
15
+ export { UseCountdownDateReturn, useCountdownDate } from './use-countdown-date/use-countdown-date.js';
16
+ export { useEventListener } from './use-event-listener/use-event-listener.js';
17
+ export { UseScrollOffsetTopReturn, useScrollOffsetTop } from './use-scroll-offset-top/use-scroll-offset-top.js';
18
+ export { UseCountdownSecondsReturn, useCountdownSeconds } from './use-countdown-seconds/use-countdown-seconds.js';
19
+ export { CopiedValue, CopyFn, UseCopyToClipboardReturn, useCopyToClipboard } from './use-copy-to-clipboard/use-copy-to-clipboard.js';
20
+ import 'react';
@@ -0,0 +1,19 @@
1
+ export * from './use-tabs';
2
+ export * from './use-boolean';
3
+ export * from './use-popover';
4
+ export * from './use-cookies';
5
+ export * from './use-debounce';
6
+ export * from './use-set-state';
7
+ export * from './use-is-client';
8
+ export * from './use-text-input';
9
+ export * from './use-back-to-top';
10
+ export * from './use-client-rect';
11
+ export * from './use-multi-select';
12
+ export * from './use-double-click';
13
+ export * from './use-local-storage';
14
+ export * from './use-popover-hover';
15
+ export * from './use-countdown-date';
16
+ export * from './use-event-listener';
17
+ export * from './use-scroll-offset-top';
18
+ export * from './use-countdown-seconds';
19
+ export * from './use-copy-to-clipboard';
@@ -0,0 +1,2 @@
1
+ export { UseBackToTopReturn, useBackToTop } from './use-back-to-top.js';
2
+ import 'react';
@@ -0,0 +1 @@
1
+ export * from './use-back-to-top';
@@ -0,0 +1,33 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+
3
+ /**
4
+ * Custom hook to manage the visibility of a "Back to Top" button based on scroll position.
5
+ *
6
+ * @param {string | number} defaultValue - The scroll progress percentage (e.g., '90%') or distance in pixels (e.g., 80) at which the button becomes visible.
7
+ * - If `defaultValue` is a percentage string (e.g., '90%'), the button becomes visible when the scroll distance is that percentage from the top.
8
+ * - If `defaultValue` is a number (e.g., 80), the button becomes visible when the scroll distance is that many pixels from the bottom.
9
+ * @param {boolean} [isDebounce=false] - Whether to debounce the scroll handler to improve performance.
10
+ *
11
+ * @returns {UseBackToTopReturn} - An object containing:
12
+ * - `isVisible`: A boolean indicating whether the "Back to Top" button should be visible.
13
+ * - `onBackToTop`: A function to scroll the window back to the top smoothly.
14
+ * - `setIsVisible`: A function to manually set the visibility of the "Back to Top" button.
15
+ *
16
+ * @example
17
+ * const { isVisible, onBackToTop } = useBackToTop('90%');
18
+ * const { isVisible, onBackToTop } = useBackToTop(80);
19
+ *
20
+ * return (
21
+ * <button onClick={onBackToTop} style={{ display: isVisible ? 'block' : 'none' }}>
22
+ * Back to Top
23
+ * </button>
24
+ * );
25
+ */
26
+ type UseBackToTopReturn = {
27
+ isVisible: boolean;
28
+ onBackToTop: () => void;
29
+ setIsVisible: Dispatch<SetStateAction<boolean>>;
30
+ };
31
+ declare function useBackToTop(defaultValue: string | number, isDebounce?: boolean): UseBackToTopReturn;
32
+
33
+ export { type UseBackToTopReturn, useBackToTop };
@@ -0,0 +1,64 @@
1
+ // src/hooks/use-back-to-top/use-back-to-top.ts
2
+ import { useMemo, useState, useEffect, useCallback } from "react";
3
+ function useBackToTop(defaultValue, isDebounce) {
4
+ const [isVisible, setIsVisible] = useState(false);
5
+ const parseValue = parseValueInput(defaultValue);
6
+ const handleScroll = useCallback(() => {
7
+ const windowInnerHeight = window.innerHeight;
8
+ const windowScrollY = Math.round(window.scrollY);
9
+ const documentOffsetHeight = document.body.offsetHeight;
10
+ const scrollProgress = Math.round(
11
+ windowScrollY / (documentOffsetHeight - windowInnerHeight) * 100
12
+ );
13
+ if (parseValue.type === "percentage") {
14
+ setIsVisible(scrollProgress >= parseValue.value);
15
+ } else {
16
+ const distanceValue = documentOffsetHeight - windowInnerHeight - windowScrollY;
17
+ setIsVisible(parseValue.value >= distanceValue);
18
+ }
19
+ }, [parseValue.type, parseValue.value]);
20
+ const debouncedHandleScroll = useMemo(() => {
21
+ let timeoutId;
22
+ return () => {
23
+ clearTimeout(timeoutId);
24
+ timeoutId = setTimeout(handleScroll, 100);
25
+ };
26
+ }, [handleScroll]);
27
+ useEffect(() => {
28
+ const scrollHandler = isDebounce ? debouncedHandleScroll : handleScroll;
29
+ window.addEventListener("scroll", scrollHandler);
30
+ return () => {
31
+ window.removeEventListener("scroll", scrollHandler);
32
+ };
33
+ }, [debouncedHandleScroll, handleScroll, isDebounce]);
34
+ const onBackToTop = () => {
35
+ window.scrollTo({ top: 0, behavior: "smooth" });
36
+ };
37
+ return {
38
+ isVisible,
39
+ onBackToTop,
40
+ setIsVisible
41
+ };
42
+ }
43
+ function parseValueInput(inputValue) {
44
+ let value;
45
+ let type;
46
+ if (typeof inputValue === "string") {
47
+ if (inputValue.endsWith("%")) {
48
+ value = Number(inputValue.slice(0, -1));
49
+ if (isNaN(value)) {
50
+ throw new Error("Invalid percentage value");
51
+ }
52
+ type = "percentage";
53
+ } else {
54
+ throw new Error("String input must end with %");
55
+ }
56
+ } else {
57
+ value = inputValue;
58
+ type = "number";
59
+ }
60
+ return { value, type };
61
+ }
62
+ export {
63
+ useBackToTop
64
+ };
@@ -0,0 +1,2 @@
1
+ export { UseBooleanReturn, useBoolean } from './use-boolean.js';
2
+ import 'react';
@@ -0,0 +1 @@
1
+ export * from './use-boolean';
@@ -0,0 +1,29 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+
3
+ /**
4
+ * Custom hook to manage a boolean state with utility functions to set it to true, false, or toggle its value.
5
+ *
6
+ * @param {boolean} [defaultValue=false] - The initial value of the boolean state.
7
+ *
8
+ * @example
9
+ * const { value, onTrue, onFalse, onToggle } = useBoolean(false);
10
+ *
11
+ * return (
12
+ * <div>
13
+ * <p>Value: {value.toString()}</p>
14
+ * <button onClick={onTrue}>Set True</button>
15
+ * <button onClick={onFalse}>Set False</button>
16
+ * <button onClick={onToggle}>Toggle</button>
17
+ * </div>
18
+ * );
19
+ */
20
+ type UseBooleanReturn = {
21
+ value: boolean;
22
+ onTrue: () => void;
23
+ onFalse: () => void;
24
+ onToggle: () => void;
25
+ setValue: Dispatch<SetStateAction<boolean>>;
26
+ };
27
+ declare function useBoolean(defaultValue?: boolean): UseBooleanReturn;
28
+
29
+ export { type UseBooleanReturn, useBoolean };
@@ -0,0 +1,24 @@
1
+ // src/hooks/use-boolean/use-boolean.ts
2
+ import { useState, useCallback } from "react";
3
+ function useBoolean(defaultValue = false) {
4
+ const [value, setValue] = useState(defaultValue);
5
+ const onTrue = useCallback(() => {
6
+ setValue(true);
7
+ }, []);
8
+ const onFalse = useCallback(() => {
9
+ setValue(false);
10
+ }, []);
11
+ const onToggle = useCallback(() => {
12
+ setValue((prev) => !prev);
13
+ }, []);
14
+ return {
15
+ value,
16
+ onTrue,
17
+ onFalse,
18
+ onToggle,
19
+ setValue
20
+ };
21
+ }
22
+ export {
23
+ useBoolean
24
+ };
@@ -0,0 +1,2 @@
1
+ export { UseClientRectReturn, useClientRect } from './use-client-rect.js';
2
+ import 'react';
@@ -0,0 +1 @@
1
+ export * from './use-client-rect';
@@ -0,0 +1,29 @@
1
+ import { RefObject } from 'react';
2
+
3
+ /**
4
+ * Custom hook to get the bounding client rect and scroll dimensions of a DOM element.
5
+ *
6
+ * @param {RefObject<HTMLDivElement>} [inputRef] - Optional ref object to the target element.
7
+ * @param {string} [eventType] - Optional event type to trigger updates (e.g., 'scroll', 'resize').
8
+ * @returns {UseClientRectReturn} - Object containing the bounding rect, scroll dimensions, and ref to the element.
9
+ */
10
+ type ScrollElValue = {
11
+ scrollWidth: number;
12
+ scrollHeight: number;
13
+ };
14
+ type DOMRectValue = {
15
+ top: number;
16
+ right: number;
17
+ bottom: number;
18
+ left: number;
19
+ x: number;
20
+ y: number;
21
+ width: number;
22
+ height: number;
23
+ };
24
+ type UseClientRectReturn = DOMRectValue & ScrollElValue & {
25
+ elementRef: RefObject<HTMLDivElement>;
26
+ };
27
+ declare function useClientRect(inputRef?: RefObject<HTMLDivElement>, eventType?: string): UseClientRectReturn;
28
+
29
+ export { type UseClientRectReturn, useClientRect };
@@ -0,0 +1,47 @@
1
+ // src/hooks/use-client-rect/use-client-rect.ts
2
+ import { useRef, useMemo, useState, useEffect, useCallback, useLayoutEffect } from "react";
3
+ function useClientRect(inputRef, eventType) {
4
+ const initialRef = useRef(null);
5
+ const elementRef = inputRef || initialRef;
6
+ const [rect, setRect] = useState(void 0);
7
+ const [scroll, setScroll] = useState(void 0);
8
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
9
+ const handleBoundingClientRect = useCallback(() => {
10
+ if (elementRef.current) {
11
+ const clientRect = elementRef.current.getBoundingClientRect();
12
+ setRect(clientRect);
13
+ setScroll({
14
+ scrollWidth: elementRef.current.scrollWidth,
15
+ scrollHeight: elementRef.current.scrollHeight
16
+ });
17
+ }
18
+ }, [elementRef]);
19
+ useIsomorphicLayoutEffect(() => {
20
+ handleBoundingClientRect();
21
+ }, [handleBoundingClientRect]);
22
+ useEffect(() => {
23
+ const event = eventType || "resize";
24
+ window.addEventListener(event, handleBoundingClientRect);
25
+ return () => {
26
+ window.removeEventListener(event, handleBoundingClientRect);
27
+ };
28
+ }, [eventType, handleBoundingClientRect]);
29
+ const memoizedRectValue = useMemo(() => rect, [rect]);
30
+ const memoizedScrollValue = useMemo(() => scroll, [scroll]);
31
+ return {
32
+ elementRef,
33
+ top: memoizedRectValue?.top ?? 0,
34
+ right: memoizedRectValue?.right ?? 0,
35
+ bottom: memoizedRectValue?.bottom ?? 0,
36
+ left: memoizedRectValue?.left ?? 0,
37
+ x: memoizedRectValue?.x ?? 0,
38
+ y: memoizedRectValue?.y ?? 0,
39
+ width: memoizedRectValue?.width ?? 0,
40
+ height: memoizedRectValue?.height ?? 0,
41
+ scrollWidth: memoizedScrollValue?.scrollWidth ?? 0,
42
+ scrollHeight: memoizedScrollValue?.scrollHeight ?? 0
43
+ };
44
+ }
45
+ export {
46
+ useClientRect
47
+ };
@@ -0,0 +1 @@
1
+ export { UseCookiesReturn, useCookies } from './use-cookies.js';
@@ -0,0 +1 @@
1
+ export * from './use-cookies';
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Custom hook to manage state with cookies.
3
+ *
4
+ * @param {string} key - The key for the cookie.
5
+ * @param {T} initialState - The initial state value.
6
+ * @param {T} defaultValues - The default values to reset to.
7
+ * @param {Object} [options] - Optional settings.
8
+ * @param {number} [options.daysUntilExpiration] - Number of days until the cookie expires.
9
+ *
10
+ * @returns {UseCookiesReturn<T>} - An object containing:
11
+ * - `state`: The current state.
12
+ * - `resetState`: A function to reset the state to default values.
13
+ * - `setState`: A function to update the state.
14
+ * - `setField`: A function to update a specific field in the state.
15
+ *
16
+ * @example
17
+ * const { state, setState, setField, resetState } = useCookies('user', { name: '', age: 0 }, { name: '', age: 0 });
18
+ *
19
+ * return (
20
+ * <div>
21
+ * <p>Name: {state.name}</p>
22
+ * <p>Age: {state.age}</p>
23
+ * <button onClick={() => setField('name', 'John')}>Set Name</button>
24
+ * <button onClick={resetState}>Reset</button>
25
+ * </div>
26
+ * );
27
+ */
28
+ type UseCookiesReturn<T> = {
29
+ state: T;
30
+ resetState: (defaultState?: T) => void;
31
+ setState: (updateState: T | Partial<T>) => void;
32
+ setField: (name: keyof T, updateValue: T[keyof T]) => void;
33
+ };
34
+ declare function useCookies<T>(key: string, initialState?: T, options?: {
35
+ initOnLoad?: boolean;
36
+ daysUntilExpiration?: number;
37
+ }): UseCookiesReturn<T>;
38
+
39
+ export { type UseCookiesReturn, useCookies };
@@ -0,0 +1,110 @@
1
+ // src/hooks/use-cookies/use-cookies.ts
2
+ import { useMemo, useState, useEffect, useCallback } from "react";
3
+
4
+ // src/utils/cookies/cookies.ts
5
+ function getCookie(key) {
6
+ try {
7
+ const keyName = `${key}=`;
8
+ const cDecoded = decodeURIComponent(document.cookie);
9
+ const cArr = cDecoded.split("; ");
10
+ for (const val of cArr) {
11
+ if (val.startsWith(keyName)) {
12
+ const cookieValue = val.substring(keyName.length);
13
+ try {
14
+ return JSON.parse(cookieValue);
15
+ } catch {
16
+ return cookieValue;
17
+ }
18
+ }
19
+ }
20
+ } catch {
21
+ return null;
22
+ }
23
+ return null;
24
+ }
25
+ function setCookie(key, value, daysUntilExpiration = 0) {
26
+ try {
27
+ const serializedValue = encodeURIComponent(JSON.stringify(value));
28
+ let cookieOptions = `${key}=${serializedValue}; path=/`;
29
+ if (daysUntilExpiration > 0) {
30
+ const expirationDate = new Date(Date.now() + daysUntilExpiration * 24 * 60 * 60 * 1e3);
31
+ cookieOptions += `; expires=${expirationDate.toUTCString()}`;
32
+ }
33
+ document.cookie = cookieOptions;
34
+ } catch (error) {
35
+ console.error("Error while setting cookie:", error);
36
+ }
37
+ }
38
+ function removeCookie(key) {
39
+ try {
40
+ document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
41
+ } catch (error) {
42
+ console.error("Error while removing cookie:", error);
43
+ }
44
+ }
45
+
46
+ // src/hooks/use-cookies/use-cookies.ts
47
+ function useCookies(key, initialState, options) {
48
+ const isValuePresent = !!getCookie(key);
49
+ const storedValue = getCookie(key) ?? initialState;
50
+ const [state, set] = useState(storedValue);
51
+ const { initOnLoad = true, daysUntilExpiration } = options ?? {};
52
+ const hasMultipleValues = state && typeof state === "object";
53
+ useEffect(() => {
54
+ if (storedValue) {
55
+ if (hasMultipleValues) {
56
+ set((prevValue) => ({ ...prevValue, ...storedValue }));
57
+ } else {
58
+ set(storedValue);
59
+ }
60
+ if (!isValuePresent && initOnLoad) {
61
+ setCookie(key, storedValue, daysUntilExpiration);
62
+ }
63
+ }
64
+ }, []);
65
+ const setState = useCallback(
66
+ (updateState) => {
67
+ if (hasMultipleValues) {
68
+ set((prevValue) => {
69
+ const updatedState = { ...prevValue, ...updateState };
70
+ setCookie(key, updatedState, daysUntilExpiration);
71
+ return updatedState;
72
+ });
73
+ } else {
74
+ setCookie(key, updateState, daysUntilExpiration);
75
+ set(updateState);
76
+ }
77
+ },
78
+ [hasMultipleValues, key, daysUntilExpiration]
79
+ );
80
+ const setField = useCallback(
81
+ (name, updateValue) => {
82
+ if (hasMultipleValues) {
83
+ setState({ [name]: updateValue });
84
+ }
85
+ },
86
+ [hasMultipleValues, setState]
87
+ );
88
+ const resetState = useCallback(
89
+ (defaultState) => {
90
+ if (defaultState) {
91
+ set(defaultState);
92
+ }
93
+ removeCookie(key);
94
+ },
95
+ [key]
96
+ );
97
+ const memoizedValue = useMemo(
98
+ () => ({
99
+ state,
100
+ setState,
101
+ setField,
102
+ resetState
103
+ }),
104
+ [resetState, setField, setState, state]
105
+ );
106
+ return memoizedValue;
107
+ }
108
+ export {
109
+ useCookies
110
+ };
@@ -0,0 +1 @@
1
+ export { CopiedValue, CopyFn, UseCopyToClipboardReturn, useCopyToClipboard } from './use-copy-to-clipboard.js';
@@ -0,0 +1 @@
1
+ export * from './use-copy-to-clipboard';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Custom hook to copy text to the clipboard.
3
+ *
4
+ * @returns {UseCopyToClipboardReturn} - An object containing:
5
+ * - `copy`: A function to copy text to the clipboard.
6
+ * - `copiedText`: The last copied text or null if nothing has been copied.
7
+ *
8
+ * @example
9
+ * const { copy, copiedText } = useCopyToClipboard();
10
+ *
11
+ * return (
12
+ * <div>
13
+ * <button onClick={() => copy('Hello, World!')}>Copy Text</button>
14
+ * {copiedText && <p>Copied: {copiedText}</p>}
15
+ * </div>
16
+ * );
17
+ */
18
+ type UseCopyToClipboardReturn = {
19
+ copy: CopyFn;
20
+ copiedText: CopiedValue;
21
+ };
22
+ type CopiedValue = string | null;
23
+ type CopyFn = (text: string) => Promise<boolean>;
24
+ declare function useCopyToClipboard(): UseCopyToClipboardReturn;
25
+
26
+ export { type CopiedValue, type CopyFn, type UseCopyToClipboardReturn, useCopyToClipboard };
@@ -0,0 +1,27 @@
1
+ // src/hooks/use-copy-to-clipboard/use-copy-to-clipboard.ts
2
+ import { useState, useCallback } from "react";
3
+ function useCopyToClipboard() {
4
+ const [copiedText, setCopiedText] = useState(null);
5
+ const copy = useCallback(
6
+ async (text) => {
7
+ if (!navigator?.clipboard) {
8
+ console.warn("Clipboard not supported");
9
+ return false;
10
+ }
11
+ try {
12
+ await navigator.clipboard.writeText(text);
13
+ setCopiedText(text);
14
+ return true;
15
+ } catch (error) {
16
+ console.warn("Copy failed", error);
17
+ setCopiedText(null);
18
+ return false;
19
+ }
20
+ },
21
+ [setCopiedText]
22
+ );
23
+ return { copy, copiedText };
24
+ }
25
+ export {
26
+ useCopyToClipboard
27
+ };
@@ -0,0 +1 @@
1
+ export { UseCountdownDateReturn, useCountdownDate } from './use-countdown-date.js';
@@ -0,0 +1 @@
1
+ export * from './use-countdown-date';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Custom hook to create a countdown timer to a target date.
3
+ *
4
+ * @param {Date} targetDate - The target date to count down to.
5
+ * @param {string} [placeholder='- -'] - The placeholder value to display before the countdown starts.
6
+ *
7
+ * @returns {UseCountdownDateReturn} - An object containing the current countdown values in days, hours, minutes, and seconds.
8
+ *
9
+ * @example
10
+ * const { days, hours, minutes, seconds } = useCountdownDate(new Date('2023-12-31T23:59:59'));
11
+ *
12
+ * return (
13
+ * <div>
14
+ * <p>Days: {days}</p>
15
+ * <p>Hours: {hours}</p>
16
+ * <p>Minutes: {minutes}</p>
17
+ * <p>Seconds: {seconds}</p>
18
+ * </div>
19
+ * );
20
+ */
21
+ type UseCountdownDateReturn = {
22
+ days: string;
23
+ hours: string;
24
+ minutes: string;
25
+ seconds: string;
26
+ };
27
+ declare function useCountdownDate(targetDate: Date, placeholder?: string): UseCountdownDateReturn;
28
+
29
+ export { type UseCountdownDateReturn, useCountdownDate };
@@ -0,0 +1,41 @@
1
+ // src/hooks/use-countdown-date/use-countdown-date.ts
2
+ import { useState, useEffect, useCallback } from "react";
3
+ function useCountdownDate(targetDate, placeholder = "- -") {
4
+ const [value, setValue] = useState({
5
+ days: placeholder,
6
+ hours: placeholder,
7
+ minutes: placeholder,
8
+ seconds: placeholder
9
+ });
10
+ const handleUpdate = useCallback(() => {
11
+ const now = /* @__PURE__ */ new Date();
12
+ const { days, hours, minutes, seconds } = calculateTimeDifference(targetDate, now);
13
+ setValue({
14
+ days: formatTime(days),
15
+ hours: formatTime(hours),
16
+ minutes: formatTime(minutes),
17
+ seconds: formatTime(seconds)
18
+ });
19
+ }, [targetDate]);
20
+ useEffect(() => {
21
+ handleUpdate();
22
+ const interval = setInterval(handleUpdate, 1e3);
23
+ return () => clearInterval(interval);
24
+ }, []);
25
+ return value;
26
+ }
27
+ function formatTime(value) {
28
+ return String(value).length === 1 ? `0${value}` : `${value}`;
29
+ }
30
+ function calculateTimeDifference(futureDate, currentDate) {
31
+ const distance = futureDate.getTime() - currentDate.getTime();
32
+ return {
33
+ days: Math.floor(distance / (1e3 * 60 * 60 * 24)),
34
+ hours: Math.floor(distance % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60)),
35
+ minutes: Math.floor(distance % (1e3 * 60 * 60) / (1e3 * 60)),
36
+ seconds: Math.floor(distance % (1e3 * 60) / 1e3)
37
+ };
38
+ }
39
+ export {
40
+ useCountdownDate
41
+ };
@@ -0,0 +1,2 @@
1
+ export { UseCountdownSecondsReturn, useCountdownSeconds } from './use-countdown-seconds.js';
2
+ import 'react';
@@ -0,0 +1 @@
1
+ export * from './use-countdown-seconds';
@@ -0,0 +1,35 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+
3
+ /**
4
+ * Custom hook to create a countdown timer in seconds.
5
+ *
6
+ * @param {number} defaultValue - The initial countdown value in seconds.
7
+ *
8
+ * @returns {UseCountdownSecondsReturn} - An object containing:
9
+ * - `value`: The current countdown value in seconds.
10
+ * - `start`: A function to start the countdown.
11
+ * - `reset`: A function to reset the countdown to the initial value.
12
+ * - `isCounting`: A boolean indicating whether the countdown is currently active.
13
+ * - `setValue`: A function to manually set the countdown value.
14
+ *
15
+ * @example
16
+ * const { value, start, reset, isCounting } = useCountdownSeconds(30);
17
+ *
18
+ * return (
19
+ * <div>
20
+ * <p>Countdown: {value} seconds</p>
21
+ * <button onClick={start} disabled={isCounting}>Start</button>
22
+ * <button onClick={reset}>Reset</button>
23
+ * </div>
24
+ * );
25
+ */
26
+ type UseCountdownSecondsReturn = {
27
+ value: number;
28
+ start: () => void;
29
+ reset: () => void;
30
+ isCounting: boolean;
31
+ setValue: Dispatch<SetStateAction<number>>;
32
+ };
33
+ declare function useCountdownSeconds(defaultValue: number): UseCountdownSecondsReturn;
34
+
35
+ export { type UseCountdownSecondsReturn, useCountdownSeconds };