kitzo 2.5.1 → 2.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
+ import { Dispatch } from 'react';
1
2
  import { JSX } from 'react/jsx-runtime';
2
3
  import { PropsWithChildren } from 'react';
3
4
  import { ReactNode } from 'react';
5
+ import { SetStateAction } from 'react';
4
6
 
5
7
  declare type AnimationOptions = {
6
8
  duration?: number;
@@ -13,6 +15,40 @@ declare type AnimationOptions = {
13
15
 
14
16
  declare type CopyStatus = 'standby' | 'copying' | 'copied' | 'error';
15
17
 
18
+ declare type DebouncedFunction<Args extends unknown[]> = {
19
+ /**
20
+ * The debounced version of your callback.
21
+ * @param args - The arguments passed to the original callback.
22
+ */
23
+ (...args: Args): void;
24
+ /**
25
+ * Cancels any scheduled execution of the debounced callback.
26
+ */
27
+ cancel: () => void;
28
+ /**
29
+ * Immediately invokes the pending execution of the debounced callback and cancels the timer.
30
+ */
31
+ flush: () => void;
32
+ };
33
+
34
+ declare type DebounceOptions = {
35
+ /**
36
+ * If true, the callback is invoked on the leading edge of the timeout (immediately on the first call).
37
+ * @default false
38
+ */
39
+ leading?: boolean;
40
+ /**
41
+ * If true, the callback is invoked on the trailing edge of the timeout (after the delay has passed).
42
+ * @default true
43
+ */
44
+ trailing?: boolean;
45
+ /**
46
+ * The number of milliseconds to delay execution.
47
+ * @default 300
48
+ */
49
+ delay?: number;
50
+ };
51
+
16
52
  declare type Options = ToastOptionsWithoutType;
17
53
 
18
54
  declare type PromiseToastFn = <T, E = unknown>(promise: Promise<T>, msgs: PromiseToastMsgs<T, E>, options?: PromiseToastOptions) => Promise<T>;
@@ -90,8 +126,8 @@ declare type TooltipCoreProps = {
90
126
  smartHover?: boolean;
91
127
  hideOnTouch?: boolean;
92
128
  animation?: TooltipAnimation;
93
- isHidden?: boolean;
94
- isDark?: boolean;
129
+ hidden?: boolean;
130
+ dark?: boolean;
95
131
  };
96
132
 
97
133
  export declare type TooltipPosition = 'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end';
@@ -114,6 +150,25 @@ declare type UseCopyReturn = {
114
150
 
115
151
  export declare function useDebounce<T>(value: T, delay?: number): T;
116
152
 
153
+ /**
154
+ * A hook that returns a memoized debounced function to limit the execution rate of a callback.
155
+ * * @template Args - The type of arguments accepted by the callback.
156
+ * @param callback - The function to debounce.
157
+ * @param options - Configuration for leading/trailing edges and delay.
158
+ * @returns A debounced function with `.cancel()` and `.flush()` methods.
159
+ */
160
+ export declare function useDebouncedCallback<Args extends unknown[]>(callback: (...args: Args) => void, options?: DebounceOptions): DebouncedFunction<Args>;
161
+
162
+ /**
163
+ * A custom hook that manages a stateful value in `localStorage`,
164
+ * ensuring synchronization across multiple tabs and components.
165
+ * @example
166
+ * const [theme, setTheme] = useLocalStorage<'light' | 'dark'>('ui-theme', 'light');
167
+ * // Supports functional updates:
168
+ * setTheme(prev => prev === 'light' ? 'dark' : 'light');
169
+ */
170
+ export declare function useLocalStorage<T>(key: string, initialValue: T): [T, Dispatch<SetStateAction<T>>];
171
+
117
172
  export declare function useThrottle<T>(value: T, delay?: number): T;
118
173
 
119
174
  export declare function useWindowSize(updateDelay?: number): {
package/dist/index.js CHANGED
@@ -2,15 +2,19 @@ import { Toaster as r } from "./react/components/toast/Toaster.js";
2
2
  import { Tooltip as p } from "./react/components/tooltip/Tooltip.js";
3
3
  import { toast as m } from "./react/components/toast/service/triggerToasts.js";
4
4
  import { useCopy as s } from "./react/hooks/useCopy.js";
5
- import { useDebounce as i } from "./react/hooks/useDebounce.js";
6
- import { useThrottle as a } from "./react/hooks/useThrottle.js";
7
- import { useWindowSize as n } from "./react/hooks/useWindowSize.js";
5
+ import { useDebounce as a } from "./react/hooks/useDebounce.js";
6
+ import { useDebouncedCallback as c } from "./react/hooks/useDebouncedCallback.js";
7
+ import { useLocalStorage as i } from "./react/hooks/useLocalStorage.js";
8
+ import { useThrottle as T } from "./react/hooks/useThrottle.js";
9
+ import { useWindowSize as C } from "./react/hooks/useWindowSize.js";
8
10
  export {
9
11
  r as Toaster,
10
12
  p as Tooltip,
11
13
  m as toast,
12
14
  s as useCopy,
13
- i as useDebounce,
14
- a as useThrottle,
15
- n as useWindowSize
15
+ a as useDebounce,
16
+ c as useDebouncedCallback,
17
+ i as useLocalStorage,
18
+ T as useThrottle,
19
+ C as useWindowSize
16
20
  };
@@ -1,35 +1,35 @@
1
1
  import { jsx as a, Fragment as r, jsxs as T } from "react/jsx-runtime";
2
- import d from "react";
2
+ import c from "react";
3
3
  import v from "./helpers/addTooltipStyles.js";
4
- import w from "./helpers/getPositionClass.js";
5
- import O from "./partials/TooltipWrapper.js";
6
- import k from "./helpers/getAnimationProperties.js";
7
- function C(h) {
4
+ import k from "./helpers/getPositionClass.js";
5
+ import w from "./partials/TooltipWrapper.js";
6
+ import O from "./helpers/getAnimationProperties.js";
7
+ function z(h) {
8
8
  const {
9
9
  content: n,
10
10
  children: t,
11
11
  position: y = "top",
12
12
  animation: i = !0,
13
- isHidden: s = !1,
13
+ hidden: s = !1,
14
14
  offset: m = 8,
15
15
  smartHover: f = !0,
16
16
  hideOnTouch: l = !0,
17
- isDark: u
18
- } = h, [D, b] = d.useState(!1);
19
- if (d.useEffect(() => {
20
- b(!0), v();
21
- }, []), !D) return /* @__PURE__ */ a(r, { children: t });
17
+ dark: u
18
+ } = h, [b, x] = c.useState(!1);
19
+ if (c.useEffect(() => {
20
+ x(!0), v();
21
+ }, []), !b) return /* @__PURE__ */ a(r, { children: t });
22
22
  if (typeof s == "boolean" && s) return /* @__PURE__ */ a(r, { children: t });
23
23
  if (n == null)
24
24
  return /* @__PURE__ */ a(r, { children: t });
25
- const o = {
25
+ const e = {
26
26
  offset: isNaN(Number(m)) ? 8 : Number(m),
27
27
  smartHover: typeof f == "boolean" ? f : !0,
28
28
  hideOnTouch: typeof l == "boolean" ? l : !0
29
29
  };
30
- let p = !1, c = !1;
31
- if (typeof window < "u" && (c = window.matchMedia("(pointer: coarse)").matches || navigator.maxTouchPoints > 0, p = typeof u == "boolean" ? u : window.matchMedia("(prefers-color-scheme: dark)").matches), c && o.hideOnTouch) return t;
32
- const x = w(y), M = !!i, e = k(
30
+ let p = !1, d = !1;
31
+ if (typeof window < "u" && (d = window.matchMedia("(pointer: coarse)").matches || navigator.maxTouchPoints > 0, p = typeof u == "boolean" ? u : window.matchMedia("(prefers-color-scheme: dark)").matches), d && e.hideOnTouch) return t;
32
+ const D = k(y), M = !!i, o = O(
33
33
  i === !0 ? {} : i
34
34
  );
35
35
  return /* @__PURE__ */ T(
@@ -37,25 +37,25 @@ function C(h) {
37
37
  {
38
38
  style: {
39
39
  position: "relative",
40
- width: "fit-content",
41
- "--offset": Math.max(0, o.offset),
40
+ inlineSize: "fit-content",
41
+ "--offset": Math.max(0, e.offset),
42
42
  "--startDuration": Math.max(
43
43
  0,
44
- e.startDuration
44
+ o.startDuration
45
45
  ),
46
- "--endDuration": Math.max(0, e.endDuration),
47
- "--startDelay": Math.max(0, e.startDelay),
48
- "--endDelay": Math.max(0, e.endDelay)
46
+ "--endDuration": Math.max(0, o.endDuration),
47
+ "--startDelay": Math.max(0, o.startDelay),
48
+ "--endDelay": Math.max(0, o.endDelay)
49
49
  },
50
- className: `kitzo-tooltip-root ${p ? "tooltip-theme-dark" : ""} ${o.smartHover ? "smart-hover" : ""} ${M ? "animate-tooltip" : ""}`,
50
+ className: `kitzo-tooltip-root ${p ? "dark tooltip-theme-dark" : ""} ${e.smartHover ? "smart-hover" : ""} ${M ? "animate-tooltip" : ""}`,
51
51
  children: [
52
52
  t,
53
53
  /* @__PURE__ */ a(
54
- O,
54
+ w,
55
55
  {
56
56
  content: n,
57
- positionClass: x,
58
- finalOptions: o
57
+ positionClass: D,
58
+ finalOptions: e
59
59
  }
60
60
  )
61
61
  ]
@@ -63,5 +63,5 @@ function C(h) {
63
63
  );
64
64
  }
65
65
  export {
66
- C as Tooltip
66
+ z as Tooltip
67
67
  };
@@ -1,4 +1,5 @@
1
- const o = `.kitzo-tooltip-root {
1
+ const o = `/*! Default styling */
2
+ .kitzo-tooltip-root {
2
3
  --bg-clr: hsl(0, 0%, 15%);
3
4
  --text-clr: hsl(0, 0%, 95%);
4
5
 
@@ -6,6 +7,8 @@ const o = `.kitzo-tooltip-root {
6
7
  --transition-endDuration: calc(var(--endDuration) * 1ms);
7
8
  --transition-startDelay: calc(var(--startDelay) * 1ms);
8
9
  --transition-endDelay: calc(var(--endDelay) * 1ms);
10
+
11
+ --tooltip-offset: calc(var(--offset) * 1px + 1px);
9
12
  }
10
13
 
11
14
  .kitzo-tooltip-root.tooltip-theme-dark {
@@ -32,12 +35,11 @@ const o = `.kitzo-tooltip-root {
32
35
  color: var(--text-clr);
33
36
  padding-block: 0.25rem;
34
37
  padding-inline: 0.5rem;
35
- border-radius: 0.325rem;
38
+ border-radius: 0.425rem;
36
39
  }
37
40
 
38
- /* Tooltip positioning */
41
+ /*! Tooltip transitions */
39
42
  .kitzo-tooltip-wrapper {
40
- --tooltip-offset: calc(var(--offset) * 1px + 1px);
41
43
  opacity: 0;
42
44
  transition-property: opacity;
43
45
  transition-delay: calc(
@@ -50,80 +52,6 @@ const o = `.kitzo-tooltip-root {
50
52
  transition-delay: 0ms;
51
53
  }
52
54
 
53
- /* Top */
54
- .kitzo-tooltip-wrapper.top {
55
- bottom: 100%;
56
- padding-block-end: var(--tooltip-offset);
57
- }
58
- .kitzo-tooltip-wrapper.top {
59
- left: 50%;
60
- translate: -50% 0;
61
- }
62
- .kitzo-tooltip-wrapper.top.start {
63
- left: 0;
64
- translate: 0 0;
65
- }
66
- .kitzo-tooltip-wrapper.top.end {
67
- left: auto;
68
- right: 0;
69
- translate: 0 0;
70
- }
71
-
72
- /* Right */
73
- .kitzo-tooltip-wrapper.right {
74
- left: 100%;
75
- padding-inline-start: var(--tooltip-offset);
76
- }
77
- .kitzo-tooltip-wrapper.right {
78
- top: 50%;
79
- translate: 0 -50%;
80
- }
81
- .kitzo-tooltip-wrapper.right.start {
82
- top: 0;
83
- translate: 0 0;
84
- }
85
- .kitzo-tooltip-wrapper.right.end {
86
- top: 100%;
87
- translate: 0 -100%;
88
- }
89
-
90
- /* Bottom */
91
- .kitzo-tooltip-wrapper.bottom {
92
- top: 100%;
93
- padding-block-start: var(--tooltip-offset);
94
- }
95
- .kitzo-tooltip-wrapper.bottom {
96
- left: 50%;
97
- translate: -50% 0;
98
- }
99
- .kitzo-tooltip-wrapper.bottom.start {
100
- left: 0;
101
- translate: 0 0;
102
- }
103
- .kitzo-tooltip-wrapper.bottom.end {
104
- left: 100%;
105
- translate: -100% 0;
106
- }
107
-
108
- /* Left */
109
- .kitzo-tooltip-wrapper.left {
110
- right: 100%;
111
- padding-inline-end: var(--tooltip-offset);
112
- }
113
- .kitzo-tooltip-wrapper.left {
114
- top: 50%;
115
- translate: 0 -50%;
116
- }
117
- .kitzo-tooltip-wrapper.left.start {
118
- top: 0;
119
- translate: 0 0;
120
- }
121
- .kitzo-tooltip-wrapper.left.end {
122
- top: 100%;
123
- translate: 0 -100%;
124
- }
125
-
126
- /* Tooltip transitions */
127
55
  .kitzo-tooltip-root.animate-tooltip {
128
56
  .kitzo-tooltip-content {
129
57
  text-rendering: optimizeLegibility;
@@ -170,7 +98,7 @@ const o = `.kitzo-tooltip-root {
170
98
  }
171
99
  }
172
100
 
173
- /* smart hover persistence feature */
101
+ /*! smart hover persistence feature */
174
102
  .kitzo-tooltip-root {
175
103
  .kitzo-tooltip-wrapper {
176
104
  pointer-events: none;
@@ -180,7 +108,73 @@ const o = `.kitzo-tooltip-root {
180
108
  .kitzo-tooltip-wrapper {
181
109
  pointer-events: all;
182
110
  }
183
- }`;
111
+ }
112
+
113
+ /*! Tooltip positioning */
114
+ /*? Top */
115
+ .kitzo-tooltip-wrapper[data-position^='top'] {
116
+ bottom: 100%;
117
+ padding-block-end: var(--tooltip-offset);
118
+ }
119
+ .kitzo-tooltip-wrapper[data-position='top'] {
120
+ left: 50%;
121
+ translate: -50% 0;
122
+ }
123
+ .kitzo-tooltip-wrapper[data-position='top-start'] {
124
+ left: 0;
125
+ }
126
+ .kitzo-tooltip-wrapper[data-position='top-end'] {
127
+ right: 0;
128
+ }
129
+
130
+ /*? Right */
131
+ .kitzo-tooltip-wrapper[data-position^='right'] {
132
+ inset-inline-start: 100%;
133
+ padding-inline-start: var(--tooltip-offset);
134
+ }
135
+ .kitzo-tooltip-wrapper[data-position='right'] {
136
+ top: 50%;
137
+ translate: 0 -50%;
138
+ }
139
+ .kitzo-tooltip-wrapper[data-position='right-start'] {
140
+ top: 0;
141
+ }
142
+ .kitzo-tooltip-wrapper[data-position='right-end'] {
143
+ bottom: 0;
144
+ }
145
+
146
+ /*? Bottom */
147
+ .kitzo-tooltip-wrapper[data-position^='bottom'] {
148
+ top: 100%;
149
+ padding-block-start: var(--tooltip-offset);
150
+ }
151
+ .kitzo-tooltip-wrapper[data-position='bottom'] {
152
+ left: 50%;
153
+ translate: -50% 0;
154
+ }
155
+ .kitzo-tooltip-wrapper[data-position='bottom-start'] {
156
+ left: 0;
157
+ }
158
+ .kitzo-tooltip-wrapper[data-position='bottom-end'] {
159
+ right: 0;
160
+ }
161
+
162
+ /*? Left */
163
+ .kitzo-tooltip-wrapper[data-position^='left'] {
164
+ inset-inline-end: 100%;
165
+ padding-inline-end: var(--tooltip-offset);
166
+ }
167
+ .kitzo-tooltip-wrapper[data-position='left'] {
168
+ top: 50%;
169
+ translate: 0 -50%;
170
+ }
171
+ .kitzo-tooltip-wrapper[data-position='left-start'] {
172
+ top: 0;
173
+ }
174
+ .kitzo-tooltip-wrapper[data-position='left-end'] {
175
+ bottom: 0;
176
+ }
177
+ `;
184
178
  function i() {
185
179
  if (!document.getElementById("kitzo-tooltip-styles")) {
186
180
  const t = document.createElement("style");
@@ -1,27 +1,22 @@
1
- const s = [
2
- "top-start",
1
+ const r = [
3
2
  "top",
3
+ "top-start",
4
4
  "top-end",
5
- "right-start",
6
5
  "right",
6
+ "right-start",
7
7
  "right-end",
8
- "bottom-start",
9
8
  "bottom",
9
+ "bottom-start",
10
10
  "bottom-end",
11
- "left-start",
12
11
  "left",
12
+ "left-start",
13
13
  "left-end"
14
14
  ];
15
- function n(t = "") {
15
+ function s(t = "") {
16
16
  t = typeof t == "string" ? t.trim().toLowerCase() : "top";
17
- const e = s.find((o) => o === t);
18
- if (!e) return "top";
19
- if (e.includes("-")) {
20
- const [o, r] = e.split("-");
21
- return `${o} ${r}`;
22
- } else
23
- return e;
17
+ const o = r.find((e) => e === t);
18
+ return o || "top";
24
19
  }
25
20
  export {
26
- n as default
21
+ s as default
27
22
  };
@@ -1,8 +1,8 @@
1
- import { jsx as e, Fragment as i } from "react/jsx-runtime";
1
+ import { jsx as e, Fragment as r } from "react/jsx-runtime";
2
2
  function l({
3
3
  content: t,
4
- positionClass: o,
5
- finalOptions: r
4
+ positionClass: i,
5
+ finalOptions: o
6
6
  }) {
7
7
  return /* @__PURE__ */ e(
8
8
  "div",
@@ -10,15 +10,15 @@ function l({
10
10
  style: {
11
11
  position: "absolute",
12
12
  whiteSpace: "pre-wrap",
13
- width: "max-content"
13
+ inlineSize: "max-content"
14
14
  },
15
- tabIndex: -1,
16
- className: `kitzo-tooltip-wrapper ${o}`,
15
+ className: `kitzo-tooltip-wrapper ${i}`,
16
+ "data-position": i,
17
17
  children: /* @__PURE__ */ e(
18
18
  "div",
19
19
  {
20
- className: `kitzo-tooltip-content ${o} ${r.arrow ? "tooltip-arrow" : ""}`,
21
- children: typeof t == "string" || typeof t == "number" ? /* @__PURE__ */ e("div", { className: "kitzo-tooltip-content-default-style", children: t }) : /* @__PURE__ */ e(i, { children: t })
20
+ className: `kitzo-tooltip-content ${i} ${o.arrow ? "tooltip-arrow" : ""}`,
21
+ children: typeof t == "string" || typeof t == "number" ? /* @__PURE__ */ e("div", { className: "kitzo-tooltip-content-default-style", children: t }) : /* @__PURE__ */ e(r, { children: t })
22
22
  }
23
23
  )
24
24
  }
@@ -0,0 +1,33 @@
1
+ import { useRef as l, useEffect as g, useMemo as p } from "react";
2
+ function b(s, m = {}) {
3
+ const { leading: i = !1, trailing: f = !0, delay: a = 300 } = m, t = l(s), r = l(null), e = l(null), n = l(!1);
4
+ g(() => {
5
+ t.current = s;
6
+ }, [s]);
7
+ const o = p(() => {
8
+ const u = (...c) => {
9
+ r.current = c;
10
+ const T = () => {
11
+ t.current(...c);
12
+ };
13
+ e.current && clearTimeout(e.current), i && !e.current ? (T(), n.current = !0) : n.current = !1, e.current = setTimeout(() => {
14
+ const d = r.current, k = f && !n.current && d;
15
+ e.current = null, n.current = !1, r.current = null, k && t.current(...d);
16
+ }, a);
17
+ };
18
+ return u.cancel = () => {
19
+ e.current && (clearTimeout(e.current), e.current = null), r.current = null, n.current = !1;
20
+ }, u.flush = () => {
21
+ if (e.current && r.current) {
22
+ const c = r.current;
23
+ u.cancel(), t.current(...c);
24
+ }
25
+ }, u;
26
+ }, [a, i, f]);
27
+ return g(() => () => {
28
+ o.cancel();
29
+ }, [o]), o;
30
+ }
31
+ export {
32
+ b as useDebouncedCallback
33
+ };
@@ -0,0 +1,34 @@
1
+ import { useCallback as c, useState as w, useEffect as i } from "react";
2
+ function u(t, r) {
3
+ const n = c(() => {
4
+ if (typeof window > "u")
5
+ return r;
6
+ try {
7
+ const e = window.localStorage.getItem(t);
8
+ return e ? JSON.parse(e) : r;
9
+ } catch (e) {
10
+ return console.warn(`Error reading localStorage key “${t}”:`, e), r;
11
+ }
12
+ }, [t, r]), [a, s] = w(n), d = c(
13
+ (e) => {
14
+ try {
15
+ const o = e instanceof Function ? e(a) : e;
16
+ s(o), typeof window < "u" && (window.localStorage.setItem(t, JSON.stringify(o)), window.dispatchEvent(new Event("local-storage-update")));
17
+ } catch (o) {
18
+ console.warn(`Error setting localStorage key “${t}”:`, o);
19
+ }
20
+ },
21
+ [t, a]
22
+ );
23
+ return i(() => {
24
+ const e = (o) => {
25
+ o.key && o.key !== t || s(n());
26
+ };
27
+ return window.addEventListener("storage", e), window.addEventListener("local-storage-update", e), () => {
28
+ window.removeEventListener("storage", e), window.removeEventListener("local-storage-update", e);
29
+ };
30
+ }, [t, n]), [a, d];
31
+ }
32
+ export {
33
+ u as useLocalStorage
34
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitzo",
3
- "version": "2.5.1",
3
+ "version": "2.5.3",
4
4
  "description": "A lightweight React micro-utility.",
5
5
  "type": "module",
6
6
  "files": [