minimal-shared 0.0.2

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 (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 };