@k8o/arte-odyssey 1.2.0 → 1.3.0

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.
@@ -13,7 +13,7 @@ const IconButton = ({
13
13
  {
14
14
  "aria-label": props.role ? label : void 0,
15
15
  className: cn(
16
- "inline-flex rounded-full bg-transparent",
16
+ "inline-flex cursor-pointer rounded-full bg-transparent",
17
17
  "hover:bg-bg-subtle",
18
18
  "focus-visible:border-transparent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info active:bg-bg-emphasize",
19
19
  bg === "base" && "bg-bg-base/90",
@@ -4,7 +4,9 @@ export * from './clipboard';
4
4
  export * from './hash';
5
5
  export * from './interval';
6
6
  export * from './local-storage';
7
+ export * from './resize';
7
8
  export * from './scroll-direction';
8
9
  export * from './step';
9
10
  export * from './timeout';
11
+ export * from './window-resize';
10
12
  export * from './window-size';
@@ -4,7 +4,9 @@ export * from "./clipboard";
4
4
  export * from "./hash";
5
5
  export * from "./interval";
6
6
  export * from "./local-storage";
7
+ export * from "./resize";
7
8
  export * from "./scroll-direction";
8
9
  export * from "./step";
9
10
  export * from "./timeout";
11
+ export * from "./window-resize";
10
12
  export * from "./window-size";
@@ -0,0 +1,7 @@
1
+ import { type RefObject } from 'react';
2
+ type Options = {
3
+ enabled?: boolean;
4
+ debounceMs?: number;
5
+ };
6
+ export declare const useResize: <T extends Element = HTMLElement>(callback: (entry: ResizeObserverEntry) => void, options?: Options) => RefObject<T | null>;
7
+ export {};
@@ -0,0 +1,37 @@
1
+ "use client";
2
+ import { useEffect, useRef } from "react";
3
+ const useResize = (callback, options = {}) => {
4
+ const { enabled = true, debounceMs } = options;
5
+ const ref = useRef(null);
6
+ const timeoutRef = useRef(null);
7
+ useEffect(() => {
8
+ if (!enabled) return;
9
+ const element = ref.current;
10
+ if (!element) return;
11
+ const observer = new ResizeObserver((entries) => {
12
+ for (const entry of entries) {
13
+ if (debounceMs !== void 0) {
14
+ if (timeoutRef.current) {
15
+ clearTimeout(timeoutRef.current);
16
+ }
17
+ timeoutRef.current = setTimeout(() => {
18
+ callback(entry);
19
+ }, debounceMs);
20
+ } else {
21
+ callback(entry);
22
+ }
23
+ }
24
+ });
25
+ observer.observe(element);
26
+ return () => {
27
+ if (timeoutRef.current) {
28
+ clearTimeout(timeoutRef.current);
29
+ }
30
+ observer.disconnect();
31
+ };
32
+ }, [callback, enabled, debounceMs]);
33
+ return ref;
34
+ };
35
+ export {
36
+ useResize
37
+ };
@@ -0,0 +1,68 @@
1
+ import { renderHook } from "vitest-browser-react";
2
+ import { useResize } from ".";
3
+ describe("useResize", () => {
4
+ it("\u8981\u7D20\u306E\u30EA\u30B5\u30A4\u30BA\u6642\u306B\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u304C\u547C\u3070\u308C\u308B", async () => {
5
+ const callback = vi.fn();
6
+ const { result } = await renderHook(() => useResize(callback));
7
+ const element = document.createElement("div");
8
+ Object.defineProperty(result.current, "current", {
9
+ writable: true,
10
+ value: element
11
+ });
12
+ const observer = new ResizeObserver(callback);
13
+ observer.observe(element);
14
+ const contentRect = new DOMRectReadOnly(0, 0, 100, 100);
15
+ const entry = {
16
+ target: element,
17
+ contentRect,
18
+ borderBoxSize: [],
19
+ contentBoxSize: [],
20
+ devicePixelContentBoxSize: []
21
+ };
22
+ callback(entry);
23
+ expect(callback).toHaveBeenCalled();
24
+ observer.disconnect();
25
+ });
26
+ it("enabled=false\u306E\u5834\u5408\u306F\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u304C\u547C\u3070\u308C\u306A\u3044", async () => {
27
+ const callback = vi.fn();
28
+ const { result } = await renderHook(
29
+ () => useResize(callback, { enabled: false })
30
+ );
31
+ expect(result.current.current).toBeNull();
32
+ expect(callback).not.toHaveBeenCalled();
33
+ });
34
+ it("debounceMs\u6307\u5B9A\u6642\u306F\u6307\u5B9A\u6642\u9593\u5F8C\u306B\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u304C\u547C\u3070\u308C\u308B", async () => {
35
+ vi.useFakeTimers();
36
+ const callback = vi.fn();
37
+ const { result } = await renderHook(
38
+ () => useResize(callback, { debounceMs: 300 })
39
+ );
40
+ const element = document.createElement("div");
41
+ Object.defineProperty(result.current, "current", {
42
+ writable: true,
43
+ value: element
44
+ });
45
+ const observer = new ResizeObserver((entries) => {
46
+ for (const entry2 of entries) {
47
+ callback(entry2);
48
+ }
49
+ });
50
+ observer.observe(element);
51
+ const contentRect = new DOMRectReadOnly(0, 0, 100, 100);
52
+ const entry = {
53
+ target: element,
54
+ contentRect,
55
+ borderBoxSize: [],
56
+ contentBoxSize: [],
57
+ devicePixelContentBoxSize: []
58
+ };
59
+ callback(entry);
60
+ expect(callback).toHaveBeenCalledTimes(1);
61
+ vi.advanceTimersByTime(299);
62
+ expect(callback).toHaveBeenCalledTimes(1);
63
+ vi.advanceTimersByTime(1);
64
+ expect(callback).toHaveBeenCalledTimes(1);
65
+ observer.disconnect();
66
+ vi.useRealTimers();
67
+ });
68
+ });
@@ -0,0 +1,10 @@
1
+ type Size = {
2
+ width: number;
3
+ height: number;
4
+ };
5
+ type Options = {
6
+ enabled?: boolean;
7
+ debounceMs?: number;
8
+ };
9
+ export declare const useWindowResize: (callback: (size: Size) => void, options?: Options) => void;
10
+ export {};
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ import { useEffect, useRef } from "react";
3
+ const useWindowResize = (callback, options = {}) => {
4
+ const { enabled = true, debounceMs } = options;
5
+ const timeoutRef = useRef(null);
6
+ useEffect(() => {
7
+ if (!enabled) return;
8
+ const handleResize = () => {
9
+ const size = {
10
+ width: window.innerWidth,
11
+ height: window.innerHeight
12
+ };
13
+ if (debounceMs !== void 0) {
14
+ if (timeoutRef.current) {
15
+ clearTimeout(timeoutRef.current);
16
+ }
17
+ timeoutRef.current = setTimeout(() => {
18
+ callback(size);
19
+ }, debounceMs);
20
+ } else {
21
+ callback(size);
22
+ }
23
+ };
24
+ window.addEventListener("resize", handleResize);
25
+ return () => {
26
+ if (timeoutRef.current) {
27
+ clearTimeout(timeoutRef.current);
28
+ }
29
+ window.removeEventListener("resize", handleResize);
30
+ };
31
+ }, [callback, enabled, debounceMs]);
32
+ };
33
+ export {
34
+ useWindowResize
35
+ };
@@ -0,0 +1,43 @@
1
+ import { renderHook } from "vitest-browser-react";
2
+ import { useWindowResize } from ".";
3
+ describe("useWindowResize", () => {
4
+ it("window\u30EA\u30B5\u30A4\u30BA\u6642\u306B\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u304C\u547C\u3070\u308C\u308B", async () => {
5
+ const resizedWindowSize = { width: 1e3, height: 1e3 };
6
+ const callback = vi.fn();
7
+ const { act } = await renderHook(() => useWindowResize(callback));
8
+ expect(callback).not.toHaveBeenCalled();
9
+ window.innerWidth = resizedWindowSize.width;
10
+ window.innerHeight = resizedWindowSize.height;
11
+ act(() => {
12
+ window.dispatchEvent(new Event("resize"));
13
+ });
14
+ expect(callback).toHaveBeenCalledWith(resizedWindowSize);
15
+ expect(callback).toHaveBeenCalledTimes(1);
16
+ });
17
+ it("enabled=false\u306E\u5834\u5408\u306F\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u304C\u547C\u3070\u308C\u306A\u3044", async () => {
18
+ const callback = vi.fn();
19
+ await renderHook(() => useWindowResize(callback, { enabled: false }));
20
+ expect(callback).not.toHaveBeenCalled();
21
+ });
22
+ it("debounceMs\u6307\u5B9A\u6642\u306F\u6307\u5B9A\u6642\u9593\u5F8C\u306B\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u304C\u547C\u3070\u308C\u308B", async () => {
23
+ vi.useFakeTimers();
24
+ const resizedWindowSize = { width: 1e3, height: 1e3 };
25
+ const callback = vi.fn();
26
+ const { act } = await renderHook(
27
+ () => useWindowResize(callback, { debounceMs: 300 })
28
+ );
29
+ expect(callback).not.toHaveBeenCalled();
30
+ window.innerWidth = resizedWindowSize.width;
31
+ window.innerHeight = resizedWindowSize.height;
32
+ act(() => {
33
+ window.dispatchEvent(new Event("resize"));
34
+ });
35
+ expect(callback).not.toHaveBeenCalled();
36
+ vi.advanceTimersByTime(299);
37
+ expect(callback).not.toHaveBeenCalled();
38
+ vi.advanceTimersByTime(1);
39
+ expect(callback).toHaveBeenCalledWith(resizedWindowSize);
40
+ expect(callback).toHaveBeenCalledTimes(1);
41
+ vi.useRealTimers();
42
+ });
43
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k8o/arte-odyssey",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "k8o's react ui library",
5
5
  "author": "k8o <kosakanoki@gmail.com>",
6
6
  "keywords": [