@musecat/functionkit 1.1.0 → 1.2.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.
Files changed (91) hide show
  1. package/package.json +17 -1
  2. package/packages/cookie/cookie.shared.ts +10 -2
  3. package/packages/utils/floatingMotion.ts +1 -3
  4. package/.agents/references/components/ScrolltoTop.md +0 -36
  5. package/.agents/references/components/SwitchCase.md +0 -47
  6. package/.agents/references/components/ViewportPortal.md +0 -34
  7. package/.agents/references/cookie/cookie.md +0 -47
  8. package/.agents/references/datetime/dateTime.client.md +0 -42
  9. package/.agents/references/datetime/dateTime.server.md +0 -42
  10. package/.agents/references/datetime/dateTime.shared.md +0 -86
  11. package/.agents/references/hooks/useAvoidKeyboard.md +0 -29
  12. package/.agents/references/hooks/useCheckInvisible.md +0 -36
  13. package/.agents/references/hooks/useCheckScroll.md +0 -36
  14. package/.agents/references/hooks/useClientDateTime.md +0 -39
  15. package/.agents/references/hooks/useDebounce.md +0 -46
  16. package/.agents/references/hooks/useDebouncedCallback.md +0 -34
  17. package/.agents/references/hooks/useDoubleClick.md +0 -40
  18. package/.agents/references/hooks/useGeolocation.md +0 -37
  19. package/.agents/references/hooks/useHasMounted.md +0 -27
  20. package/.agents/references/hooks/useIntersectionObserver.md +0 -41
  21. package/.agents/references/hooks/useInterval.md +0 -44
  22. package/.agents/references/hooks/useKeyboardHeight.md +0 -33
  23. package/.agents/references/hooks/useKeyboardListNavigation.md +0 -58
  24. package/.agents/references/hooks/useLongPress.md +0 -48
  25. package/.agents/references/hooks/usePreservedCallback.md +0 -37
  26. package/.agents/references/hooks/usePreservedReference.md +0 -34
  27. package/.agents/references/hooks/useRefEffect.md +0 -35
  28. package/.agents/references/hooks/useRelativeDateTime.md +0 -35
  29. package/.agents/references/hooks/useTimeout.md +0 -42
  30. package/.agents/references/hooks/useToggleState.md +0 -39
  31. package/.agents/references/hooks/useViewportHeight.md +0 -26
  32. package/.agents/references/hooks/useViewportMatch.md +0 -32
  33. package/.agents/references/utils/browserStorage.md +0 -41
  34. package/.agents/references/utils/buildContext.md +0 -47
  35. package/.agents/references/utils/clipboardShare.md +0 -59
  36. package/.agents/references/utils/floatingMotion.md +0 -67
  37. package/.agents/references/utils/getDeviceInfo.md +0 -43
  38. package/.agents/references/utils/isEditableKeyboardTarget.md +0 -35
  39. package/.agents/references/utils/mergeRefs.md +0 -29
  40. package/.agents/references/utils/seen.md +0 -37
  41. package/.agents/references/utils/subscribeKeyboardHeight.md +0 -35
  42. package/.gitattributes +0 -2
  43. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -31
  44. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -22
  45. package/.github/PULL_REQUEST_TEMPLATE.md +0 -22
  46. package/.github/workflows/ci.yml +0 -20
  47. package/.local/state/gh/device-id +0 -1
  48. package/.prettierrc +0 -8
  49. package/AGENTS.md +0 -119
  50. package/CODE_OF_CONDUCT.md +0 -55
  51. package/CONTRIBUTING.md +0 -39
  52. package/biome.json +0 -25
  53. package/tests/components/ScrolltoTop.test.tsx +0 -15
  54. package/tests/components/SwitchCase.test.tsx +0 -33
  55. package/tests/components/ViewportPortal.test.tsx +0 -46
  56. package/tests/cookie/cookie.test.ts +0 -192
  57. package/tests/datetime/datetime.test.ts +0 -461
  58. package/tests/hooks/useAvoidKeyboard.test.ts +0 -43
  59. package/tests/hooks/useCheckInvisible.test.ts +0 -59
  60. package/tests/hooks/useCheckScroll.test.ts +0 -23
  61. package/tests/hooks/useClientDateTime.test.ts +0 -12
  62. package/tests/hooks/useDebounce.test.ts +0 -96
  63. package/tests/hooks/useDebouncedCallback.test.ts +0 -63
  64. package/tests/hooks/useDoubleClick.test.ts +0 -82
  65. package/tests/hooks/useGeolocation.test.ts +0 -201
  66. package/tests/hooks/useHasMounted.test.ts +0 -10
  67. package/tests/hooks/useIntersectionObserver.test.ts +0 -78
  68. package/tests/hooks/useInterval.test.ts +0 -56
  69. package/tests/hooks/useKeyboardHeight.test.ts +0 -10
  70. package/tests/hooks/useKeyboardListNavigation.test.ts +0 -404
  71. package/tests/hooks/useLongPress.test.ts +0 -214
  72. package/tests/hooks/usePreservedCallback.test.ts +0 -33
  73. package/tests/hooks/usePreservedReference.test.ts +0 -42
  74. package/tests/hooks/useRefEffect.test.ts +0 -67
  75. package/tests/hooks/useRelativeDateTime.test.ts +0 -21
  76. package/tests/hooks/useTimeout.test.ts +0 -72
  77. package/tests/hooks/useToggleState.test.ts +0 -43
  78. package/tests/hooks/useViewportHeight.test.ts +0 -32
  79. package/tests/hooks/useViewportMatch.test.ts +0 -35
  80. package/tests/setup.ts +0 -9
  81. package/tests/utils/browserStorage.test.ts +0 -114
  82. package/tests/utils/buildContext.test.tsx +0 -26
  83. package/tests/utils/checkDevice.test.ts +0 -140
  84. package/tests/utils/clipboardShare.test.ts +0 -152
  85. package/tests/utils/floatingMotion.test.ts +0 -135
  86. package/tests/utils/keyboardTarget.test.ts +0 -85
  87. package/tests/utils/mergeRefs.test.ts +0 -50
  88. package/tests/utils/seen.test.ts +0 -40
  89. package/tests/utils/subscribeKeyboardHeight.test.ts +0 -172
  90. package/tsconfig.json +0 -18
  91. package/vitest.config.ts +0 -22
package/CONTRIBUTING.md DELETED
@@ -1,39 +0,0 @@
1
- # Contributing to @musecat/functionkit
2
-
3
- Thank you for your interest in contributing! We welcome bug reports, feature suggestions, and pull requests.
4
-
5
- ## Development Setup
6
-
7
- ```bash
8
- git clone https://github.com/TheTechclip/FunctionKit.git
9
- cd FunctionKit
10
- npm install
11
- ```
12
-
13
- ## Available Scripts
14
-
15
- | Command | Description |
16
- |---|---|
17
- | `npm test` | Run all tests with Vitest |
18
- | `npm run test:coverage` | Run tests with coverage report |
19
- | `npm run lint` | Lint all files with Biome |
20
- | `npm run format` | Format all files with Prettier + Biome |
21
-
22
- ## Code Standards
23
-
24
- - TypeScript strict mode is enabled — ensure your code compiles without errors.
25
- - All new features must include corresponding tests.
26
- - Hooks must start with `"use client"` directive. Pure utility functions must NOT.
27
- - Barrel exports (`index.ts`) must be updated for new public APIs.
28
- - Follow the existing code style (tabs, double quotes, semicolons).
29
-
30
- ## Pull Request Process
31
-
32
- 1. Create a feature branch from `master`.
33
- 2. Write tests for your changes.
34
- 3. Ensure `npm run lint && npm test` passes.
35
- 4. Open a pull request describing the change and its motivation.
36
-
37
- ## Questions?
38
-
39
- Feel free to open a discussion or issue for any questions.
package/biome.json DELETED
@@ -1,25 +0,0 @@
1
- {
2
- "$schema": "https://biomejs.dev/schemas/2.5.4/schema.json",
3
- "assist": { "actions": { "source": { "organizeImports": "on" } } },
4
- "linter": {
5
- "enabled": true,
6
- "rules": {
7
- "preset": "recommended"
8
- }
9
- },
10
- "formatter": {
11
- "enabled": true,
12
- "indentStyle": "tab",
13
- "indentWidth": 2,
14
- "lineWidth": 100
15
- },
16
- "javascript": {
17
- "formatter": {
18
- "quoteStyle": "double",
19
- "semicolons": "always"
20
- }
21
- },
22
- "files": {
23
- "includes": ["**", "!**/dist", "!**/coverage", "!**/node_modules"]
24
- }
25
- }
@@ -1,15 +0,0 @@
1
- import { render } from "@testing-library/react";
2
- import { describe, expect, test, vi } from "vitest";
3
- import { ScrolltoTop } from "@/packages/components/ScrolltoTop";
4
-
5
- describe("ScrolltoTop", () => {
6
- test("calls window.scrollTo(0, 0) on mount", () => {
7
- const originalScrollTo = window.scrollTo;
8
- window.scrollTo = vi.fn();
9
-
10
- render(<ScrolltoTop />);
11
- expect(window.scrollTo).toHaveBeenCalledWith(0, 0);
12
-
13
- window.scrollTo = originalScrollTo;
14
- });
15
- });
@@ -1,33 +0,0 @@
1
- import { render } from "@testing-library/react";
2
- import { describe, expect, test } from "vitest";
3
- import { SwitchCase } from "@/packages/components/SwitchCase";
4
-
5
- describe("SwitchCase", () => {
6
- const cases = {
7
- 1: <div>Case 1</div>,
8
- 2: <div>Case 2</div>,
9
- three: <div>Case Three</div>,
10
- };
11
-
12
- test("renders correctly matching case", () => {
13
- const { container } = render(<SwitchCase value={1} cases={cases} />);
14
- expect(container.textContent).toBe("Case 1");
15
- });
16
-
17
- test("renders another case", () => {
18
- const { container } = render(<SwitchCase value="three" cases={cases} />);
19
- expect(container.textContent).toBe("Case Three");
20
- });
21
-
22
- test("renders otherwise when case does not exist", () => {
23
- const { container } = render(
24
- <SwitchCase value={99} cases={cases} otherwise={<div>Fallback</div>} />,
25
- );
26
- expect(container.textContent).toBe("Fallback");
27
- });
28
-
29
- test("renders null when case does not exist and otherwise is not provided", () => {
30
- const { container } = render(<SwitchCase value={99} cases={cases} />);
31
- expect(container.innerHTML).toBe("");
32
- });
33
- });
@@ -1,46 +0,0 @@
1
- import { render, screen } from "@testing-library/react";
2
- import { beforeEach, describe, expect, test } from "vitest";
3
- import { getViewportPortalRoot, ViewportPortal } from "@/packages/components/ViewportPortal";
4
-
5
- describe("ViewportPortal", () => {
6
- beforeEach(() => {
7
- document.body.innerHTML = "";
8
- });
9
-
10
- test("getViewportPortalRoot creates a root element if it doesn't exist", () => {
11
- const root = getViewportPortalRoot();
12
- expect(root).not.toBeNull();
13
- expect(root?.id).toBe("viewport-portal-root");
14
- expect(document.getElementById("viewport-portal-root")).toBe(root);
15
- });
16
-
17
- test("getViewportPortalRoot returns existing root element if it exists", () => {
18
- const root1 = getViewportPortalRoot();
19
- const root2 = getViewportPortalRoot();
20
- expect(root1).toBe(root2);
21
- expect(document.querySelectorAll("#viewport-portal-root").length).toBe(1);
22
- });
23
-
24
- test("getViewportPortalRoot returns null when document is undefined (SSR)", () => {
25
- const origDocument = global.document;
26
- // @ts-expect-error
27
- delete global.document;
28
- expect(getViewportPortalRoot()).toBeNull();
29
- global.document = origDocument;
30
- });
31
-
32
- test("ViewportPortal renders children into the portal root", () => {
33
- render(
34
- <ViewportPortal>
35
- <div data-testid="portal-content">Portal Content</div>
36
- </ViewportPortal>,
37
- );
38
-
39
- const root = document.getElementById("viewport-portal-root");
40
- expect(root).not.toBeNull();
41
-
42
- const content = screen.getByTestId("portal-content");
43
- expect(content.textContent).toBe("Portal Content");
44
- expect(root?.contains(content)).toBe(true);
45
- });
46
- });
@@ -1,192 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
2
- import {
3
- clearAllClientCookies,
4
- clearClientCookie,
5
- getClientCookie,
6
- setClientCookie,
7
- } from "@/packages/cookie/cookie.shared";
8
- import { parseClientCookieNames } from "@/packages/cookie/cookieNames.shared";
9
-
10
- describe("cookie module", () => {
11
- beforeEach(() => {
12
- // Reset cookies
13
- Object.defineProperty(document, "cookie", {
14
- writable: true,
15
- value: "",
16
- });
17
-
18
- // Mock window location
19
- Object.defineProperty(window, "location", {
20
- writable: true,
21
- value: { hostname: "example.com", pathname: "/test/path" },
22
- });
23
- });
24
-
25
- afterEach(() => {
26
- vi.restoreAllMocks();
27
- });
28
-
29
- describe("parseClientCookieNames", () => {
30
- test("parses cookie string correctly", () => {
31
- const result = parseClientCookieNames("foo=bar; baz=qux; ; empty=");
32
- expect(result).toEqual(["foo", "baz", "empty"]);
33
- });
34
-
35
- test("returns empty array for empty string", () => {
36
- expect(parseClientCookieNames("")).toEqual([]);
37
- });
38
- });
39
-
40
- describe("getClientCookie", () => {
41
- test("returns cookie value if it exists", () => {
42
- document.cookie = "foo=bar; baz=qux";
43
- expect(getClientCookie("foo")).toBe("bar");
44
- expect(getClientCookie("baz")).toBe("qux");
45
- });
46
-
47
- test("skips cookies with empty name when parsing", () => {
48
- document.cookie = "=value; foo=bar";
49
- expect(getClientCookie("foo")).toBe("bar");
50
- });
51
-
52
- test("returns undefined if cookie does not exist", () => {
53
- document.cookie = "foo=bar";
54
- expect(getClientCookie("missing")).toBeUndefined();
55
- });
56
-
57
- test("handles undefined document", () => {
58
- const originalDocument = global.document;
59
- // @ts-expect-error
60
- delete global.document;
61
-
62
- expect(getClientCookie("foo")).toBeUndefined();
63
-
64
- global.document = originalDocument;
65
- });
66
- });
67
-
68
- describe("setClientCookie", () => {
69
- test("handles undefined document in setClientCookie", () => {
70
- const origDocument = global.document;
71
- // @ts-expect-error
72
- delete global.document;
73
- setClientCookie("foo", "bar");
74
- global.document = origDocument;
75
- });
76
-
77
- test("parseClientCookie handles malformed entries", () => {
78
- const result = parseClientCookieNames("=value; key");
79
- expect(result).toEqual(["key"]);
80
- });
81
-
82
- test("clearAllClientCookies handles empty cookie name", () => {
83
- const mockDoc = { cookie: "=1;;" };
84
- const entries = clearAllClientCookies({ documentRef: mockDoc as any });
85
- expect(Array.isArray(entries)).toBe(true);
86
- });
87
-
88
- test("clearAllClientCookies skips entries with empty name", () => {
89
- const mockDoc = { cookie: "a=1;;b=2" };
90
- const entries = clearAllClientCookies({ documentRef: mockDoc as any });
91
- // Entries with empty names should be skipped in the loop
92
- expect(entries).toEqual(["a", "b"]);
93
- });
94
-
95
- test("setClientCookie with days=0 does not add expires", () => {
96
- setClientCookie("foo", "bar", 0);
97
- expect(document.cookie).toBe("foo=bar; path=/");
98
- });
99
-
100
- test("sets cookie with name and value", () => {
101
- setClientCookie("foo", "bar");
102
- expect(document.cookie).toBe("foo=bar; path=/");
103
- });
104
-
105
- test("sets cookie with days", () => {
106
- vi.useFakeTimers();
107
- vi.setSystemTime(new Date("2020-01-01T00:00:00Z"));
108
-
109
- setClientCookie("foo", "bar", 7);
110
-
111
- const expectedDate = new Date("2020-01-08T00:00:00Z").toUTCString();
112
- expect(document.cookie).toBe(`foo=bar; expires=${expectedDate}; path=/`);
113
-
114
- vi.useRealTimers();
115
- });
116
-
117
- test("encodes cookie value", () => {
118
- setClientCookie("foo", "val ue;");
119
- expect(document.cookie).toBe("foo=val%20ue%3B; path=/");
120
- });
121
- });
122
-
123
- describe("clearClientCookie", () => {
124
- test("clears cookie with default options", () => {
125
- document.cookie = "foo=bar";
126
- clearClientCookie("foo");
127
- expect(document.cookie).toBe(
128
- "foo=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=example.com;",
129
- );
130
- });
131
-
132
- test("clears cookie with custom options", () => {
133
- const mockDoc = { cookie: "" };
134
- clearClientCookie("foo", {
135
- hostname: "custom.com",
136
- path: "/custom",
137
- documentRef: mockDoc,
138
- });
139
- expect(mockDoc.cookie).toBe(
140
- "foo=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/custom; domain=custom.com;",
141
- );
142
- });
143
- });
144
-
145
- describe("clearAllClientCookies", () => {
146
- test("clears all cookies based on documentRef.cookie", () => {
147
- const mockDoc = { cookie: "a=1; b=2" };
148
- const entries = clearAllClientCookies({ documentRef: mockDoc });
149
-
150
- expect(entries).toEqual(["a", "b"]);
151
- expect(mockDoc.cookie).toContain(
152
- "b=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/test/path; domain=com;",
153
- );
154
- });
155
-
156
- test("clears cookies using cookieStore if provided", async () => {
157
- const cookieStore = { delete: vi.fn().mockResolvedValue(undefined) };
158
- const mockDoc = { cookie: "a=1; b=2" };
159
-
160
- const entries = clearAllClientCookies({
161
- documentRef: mockDoc,
162
- cookieStore,
163
- });
164
-
165
- expect(entries).toEqual(["a", "b"]);
166
- expect(cookieStore.delete).toHaveBeenCalledWith("a");
167
- expect(cookieStore.delete).toHaveBeenCalledWith("b");
168
- });
169
-
170
- test("clears cookies from root path when includeRoot is true", () => {
171
- const mockDoc = { cookie: "a=1" };
172
- clearAllClientCookies({ documentRef: mockDoc, includeRoot: true });
173
-
174
- // The function iterates and updates document.cookie, so it will contain the last assignment.
175
- // With paths ["/", "/test/path"] and domain "example.com"
176
- expect(mockDoc.cookie).toContain(
177
- "a=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/test/path; domain=com;",
178
- );
179
- });
180
-
181
- test("uses provided cookieString instead of documentRef.cookie", () => {
182
- const mockDoc = { cookie: "a=1" };
183
- const entries = clearAllClientCookies({
184
- documentRef: mockDoc,
185
- cookieString: "x=1; y=2",
186
- });
187
-
188
- expect(entries).toEqual(["x", "y"]);
189
- expect(mockDoc.cookie).toContain("y=;");
190
- });
191
- });
192
- });