@gbgr/react-headless 0.1.0 → 0.1.1
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/accordion/useAccordion.d.ts.map +1 -1
- package/dist/accordion/useAccordion.js +1 -2
- package/dist/accordion/useAccordion.test.d.ts +2 -0
- package/dist/accordion/useAccordion.test.d.ts.map +1 -0
- package/dist/accordion/useAccordion.test.js +23 -0
- package/dist/button/useButton.d.ts.map +1 -1
- package/dist/button/useButton.test.d.ts +2 -0
- package/dist/button/useButton.test.d.ts.map +1 -0
- package/dist/button/useButton.test.js +53 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +12 -0
- package/dist/internal/composeEventHandlers.d.ts +1 -1
- package/dist/internal/composeEventHandlers.d.ts.map +1 -1
- package/dist/internal/composeEventHandlers.test.d.ts +2 -0
- package/dist/internal/composeEventHandlers.test.d.ts.map +1 -0
- package/dist/internal/composeEventHandlers.test.js +22 -0
- package/dist/internal/types.d.ts.map +1 -1
- package/dist/mode-toggle/useModeToggle.test.d.ts +2 -0
- package/dist/mode-toggle/useModeToggle.test.d.ts.map +1 -0
- package/dist/mode-toggle/useModeToggle.test.js +42 -0
- package/dist/test-setup.d.ts +2 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/dist/test-setup.js +5 -0
- package/dist/text-field/useTextField.test.d.ts +2 -0
- package/dist/text-field/useTextField.test.d.ts.map +1 -0
- package/dist/text-field/useTextField.test.js +43 -0
- package/package.json +5 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAccordion.d.ts","sourceRoot":"","sources":["../../src/accordion/useAccordion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,CAAA;AAEjD,KAAK,oBAAoB,GAAG,MAAM,GAAG,IAAI,CAAA;AACzC,KAAK,sBAAsB,GAAG,MAAM,EAAE,CAAA;AAEtC,MAAM,MAAM,iBAAiB,GAAG;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,KAAK,CAAC,EAAE,oBAAoB,GAAG,sBAAsB,CAAA;IACrD,YAAY,CAAC,EAAE,oBAAoB,GAAG,sBAAsB,CAAA;IAC5D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,GAAG,sBAAsB,KAAK,IAAI,CAAA;IAC9E;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,cAAc,GAAG;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,iBAAiB,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,GAAG;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAMD,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB;;;;4BAwCvC,MAAM;6BAUN,MAAM,YAAY,OAAO;4BA2BzB,MAAM;4BA2BR,cAAc,UAAU,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,KAOhE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,cAAc;+BAOjD,iBAAiB,UAClB,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"useAccordion.d.ts","sourceRoot":"","sources":["../../src/accordion/useAccordion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,CAAA;AAEjD,KAAK,oBAAoB,GAAG,MAAM,GAAG,IAAI,CAAA;AACzC,KAAK,sBAAsB,GAAG,MAAM,EAAE,CAAA;AAEtC,MAAM,MAAM,iBAAiB,GAAG;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,KAAK,CAAC,EAAE,oBAAoB,GAAG,sBAAsB,CAAA;IACrD,YAAY,CAAC,EAAE,oBAAoB,GAAG,sBAAsB,CAAA;IAC5D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,GAAG,sBAAsB,KAAK,IAAI,CAAA;IAC9E;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,cAAc,GAAG;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,iBAAiB,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,GAAG;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAMD,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB;;;;4BAwCvC,MAAM;6BAUN,MAAM,YAAY,OAAO;4BA2BzB,MAAM;4BA2BR,cAAc,UAAU,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,KAOhE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,cAAc;+BAOjD,iBAAiB,UAClB,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,KA2BhD,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,GAAG,cAAc;+BAO1D,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,UAC9B,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,KAevC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,cAAc;EAgB5D"}
|
|
@@ -8,8 +8,7 @@ export function useAccordion(props) {
|
|
|
8
8
|
const baseId = React.useId();
|
|
9
9
|
const [uncontrolledSingle, setUncontrolledSingle] = React.useState(typeof defaultValue === "string" ? defaultValue : null);
|
|
10
10
|
const [uncontrolledMultiple, setUncontrolledMultiple] = React.useState(Array.isArray(defaultValue) ? defaultValue : []);
|
|
11
|
-
const currentValue = value ??
|
|
12
|
-
(type === "multiple" ? uncontrolledMultiple : uncontrolledSingle);
|
|
11
|
+
const currentValue = value ?? (type === "multiple" ? uncontrolledMultiple : uncontrolledSingle);
|
|
13
12
|
const setValue = React.useCallback((next) => {
|
|
14
13
|
if (value === undefined) {
|
|
15
14
|
if (type === "multiple") {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAccordion.test.d.ts","sourceRoot":"","sources":["../../src/accordion/useAccordion.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { act, renderHook } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { useAccordion } from "./useAccordion";
|
|
4
|
+
describe("useAccordion", () => {
|
|
5
|
+
it("single 모드에서 collapsible이면 같은 아이템을 다시 누를 때 닫힌다", () => {
|
|
6
|
+
const { result } = renderHook(() => useAccordion({ type: "single", collapsible: true }));
|
|
7
|
+
act(() => {
|
|
8
|
+
result.current.toggleItem("item-a");
|
|
9
|
+
});
|
|
10
|
+
expect(result.current.value).toBe("item-a");
|
|
11
|
+
act(() => {
|
|
12
|
+
result.current.toggleItem("item-a");
|
|
13
|
+
});
|
|
14
|
+
expect(result.current.value).toBeNull();
|
|
15
|
+
});
|
|
16
|
+
it("disabled 상태에서는 토글해도 닫힌 상태를 유지한다", () => {
|
|
17
|
+
const { result } = renderHook(() => useAccordion({ type: "single", disabled: true }));
|
|
18
|
+
act(() => {
|
|
19
|
+
result.current.toggleItem("item-a");
|
|
20
|
+
});
|
|
21
|
+
expect(result.current.isItemOpen("item-a")).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useButton.d.ts","sourceRoot":"","sources":["../../src/button/useButton.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"useButton.d.ts","sourceRoot":"","sources":["../../src/button/useButton.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,aAAa,CAAA;AAErE,KAAK,gBAAgB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAA;AAE/E,MAAM,MAAM,cAAc,GAAG,IAAI,CAChC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAC7C,UAAU,GAAG,MAAM,CACnB,GAAG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAC3C,CAAA;AAkBD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc;;;;;;;iCA2EnB,MAAM;+BAER,MAAM,YAAY,OAAO;;;iBA+F5C,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,GAAG,cAAc;EAEpE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useButton.test.d.ts","sourceRoot":"","sources":["../../src/button/useButton.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { act, renderHook } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { useButton } from "./useButton";
|
|
4
|
+
describe("useButton", () => {
|
|
5
|
+
it("포인터 이벤트에 따라 상태가 전환된다", () => {
|
|
6
|
+
const { result } = renderHook(() => useButton({}));
|
|
7
|
+
act(() => {
|
|
8
|
+
result.current.events.pointerEnter();
|
|
9
|
+
});
|
|
10
|
+
expect(result.current.state).toBe("hovered");
|
|
11
|
+
act(() => {
|
|
12
|
+
result.current.events.pointerDown(1);
|
|
13
|
+
});
|
|
14
|
+
expect(result.current.state).toBe("pressed");
|
|
15
|
+
act(() => {
|
|
16
|
+
result.current.events.pointerUp(1, true);
|
|
17
|
+
});
|
|
18
|
+
expect(result.current.state).toBe("hovered");
|
|
19
|
+
act(() => {
|
|
20
|
+
result.current.events.pointerLeave();
|
|
21
|
+
});
|
|
22
|
+
expect(result.current.state).toBe("idle");
|
|
23
|
+
});
|
|
24
|
+
it("클릭 시 onPress를 호출한다", () => {
|
|
25
|
+
const onPress = vi.fn();
|
|
26
|
+
const { result } = renderHook(() => useButton({ onPress }));
|
|
27
|
+
const event = {
|
|
28
|
+
defaultPrevented: false,
|
|
29
|
+
preventDefault: vi.fn(),
|
|
30
|
+
stopPropagation: vi.fn(),
|
|
31
|
+
};
|
|
32
|
+
act(() => {
|
|
33
|
+
result.current.buttonProps.onClick?.(event);
|
|
34
|
+
});
|
|
35
|
+
expect(onPress).toHaveBeenCalledTimes(1);
|
|
36
|
+
});
|
|
37
|
+
it("disabled이면 클릭을 막고 이벤트를 중단한다", () => {
|
|
38
|
+
const onPress = vi.fn();
|
|
39
|
+
const { result } = renderHook(() => useButton({ disabled: true, onPress }));
|
|
40
|
+
const event = {
|
|
41
|
+
defaultPrevented: false,
|
|
42
|
+
preventDefault: vi.fn(),
|
|
43
|
+
stopPropagation: vi.fn(),
|
|
44
|
+
};
|
|
45
|
+
act(() => {
|
|
46
|
+
result.current.buttonProps.onClick?.(event);
|
|
47
|
+
});
|
|
48
|
+
expect(onPress).not.toHaveBeenCalled();
|
|
49
|
+
expect(event.preventDefault).toHaveBeenCalledTimes(1);
|
|
50
|
+
expect(event.stopPropagation).toHaveBeenCalledTimes(1);
|
|
51
|
+
expect(result.current.state).toBe("disabled");
|
|
52
|
+
});
|
|
53
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export type { ButtonPressEvent, UseButtonProps } from "./button/useButton";
|
|
2
|
-
export { useButton } from "./button/useButton";
|
|
3
1
|
export type { AccordionType, UseAccordionProps } from "./accordion/useAccordion";
|
|
4
2
|
export { useAccordion } from "./accordion/useAccordion";
|
|
5
|
-
export type {
|
|
3
|
+
export type { ButtonPressEvent, UseButtonProps } from "./button/useButton";
|
|
4
|
+
export { useButton } from "./button/useButton";
|
|
5
|
+
export type { ModeToggleValue, UseModeToggleProps, } from "./mode-toggle/useModeToggle";
|
|
6
6
|
export { useModeToggle } from "./mode-toggle/useModeToggle";
|
|
7
7
|
export type { UseTextFieldProps } from "./text-field/useTextField";
|
|
8
8
|
export { useTextField } from "./text-field/useTextField";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,YAAY,EACX,eAAe,EACf,kBAAkB,GAClB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,YAAY,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { useButton } from "./button/useButton";
|
|
2
1
|
export { useAccordion } from "./accordion/useAccordion";
|
|
2
|
+
export { useButton } from "./button/useButton";
|
|
3
3
|
export { useModeToggle } from "./mode-toggle/useModeToggle";
|
|
4
4
|
export { useTextField } from "./text-field/useTextField";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
describe("react-headless 엔트리 export", () => {
|
|
5
|
+
it("모든 공개 훅 export를 유지한다", () => {
|
|
6
|
+
const source = readFileSync(resolve(__dirname, "./index.ts"), "utf8");
|
|
7
|
+
expect(source).toContain('export { useAccordion }');
|
|
8
|
+
expect(source).toContain('export { useButton }');
|
|
9
|
+
expect(source).toContain('export { useModeToggle }');
|
|
10
|
+
expect(source).toContain('export { useTextField }');
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as React from "react";
|
|
1
|
+
import type * as React from "react";
|
|
2
2
|
type Handler<E> = ((event: E) => void) | undefined;
|
|
3
3
|
export declare function composeEventHandlers<E extends React.SyntheticEvent>(originalHandler: Handler<E>, ourHandler: Handler<E>, options?: {
|
|
4
4
|
checkDefaultPrevented?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composeEventHandlers.d.ts","sourceRoot":"","sources":["../../src/internal/composeEventHandlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"composeEventHandlers.d.ts","sourceRoot":"","sources":["../../src/internal/composeEventHandlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAEnC,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;AAElD,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,KAAK,CAAC,cAAc,EAClE,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC,EAC3B,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE;IAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAE,IAErC,OAAO,CAAC,UAShB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composeEventHandlers.test.d.ts","sourceRoot":"","sources":["../../src/internal/composeEventHandlers.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { composeEventHandlers } from "./composeEventHandlers";
|
|
3
|
+
describe("composeEventHandlers", () => {
|
|
4
|
+
it("기본값에서는 defaultPrevented면 내부 핸들러를 호출하지 않는다", () => {
|
|
5
|
+
const original = vi.fn((event) => {
|
|
6
|
+
event.defaultPrevented = true;
|
|
7
|
+
});
|
|
8
|
+
const ours = vi.fn();
|
|
9
|
+
const handler = composeEventHandlers(original, ours);
|
|
10
|
+
handler({ defaultPrevented: false });
|
|
11
|
+
expect(ours).not.toHaveBeenCalled();
|
|
12
|
+
});
|
|
13
|
+
it("checkDefaultPrevented를 false로 주면 항상 내부 핸들러를 호출한다", () => {
|
|
14
|
+
const original = vi.fn((event) => {
|
|
15
|
+
event.defaultPrevented = true;
|
|
16
|
+
});
|
|
17
|
+
const ours = vi.fn();
|
|
18
|
+
const handler = composeEventHandlers(original, ours, { checkDefaultPrevented: false });
|
|
19
|
+
handler({ defaultPrevented: false });
|
|
20
|
+
expect(ours).toHaveBeenCalledTimes(1);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/internal/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAAE,CAAC,GAAG,EAAE,QAAQ,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/internal/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAAE,CAAC,GAAG,EAAE,QAAQ,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useModeToggle.test.d.ts","sourceRoot":"","sources":["../../src/mode-toggle/useModeToggle.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { act, renderHook } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { useModeToggle } from "./useModeToggle";
|
|
4
|
+
describe("useModeToggle", () => {
|
|
5
|
+
it("기본값 light에서 toggleValue 호출 시 dark로 바뀐다", () => {
|
|
6
|
+
const { result } = renderHook(() => useModeToggle({ defaultValue: "light" }));
|
|
7
|
+
expect(result.current.value).toBe("light");
|
|
8
|
+
act(() => {
|
|
9
|
+
result.current.toggleValue();
|
|
10
|
+
});
|
|
11
|
+
expect(result.current.value).toBe("dark");
|
|
12
|
+
expect(result.current.buttonProps["aria-checked"]).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
it("onClick으로 값이 토글되고 onValueChange가 호출된다", () => {
|
|
15
|
+
const onValueChange = vi.fn();
|
|
16
|
+
const { result } = renderHook(() => useModeToggle({ onValueChange }));
|
|
17
|
+
const event = {
|
|
18
|
+
defaultPrevented: false,
|
|
19
|
+
preventDefault: vi.fn(),
|
|
20
|
+
stopPropagation: vi.fn(),
|
|
21
|
+
};
|
|
22
|
+
act(() => {
|
|
23
|
+
result.current.buttonProps.onClick?.(event);
|
|
24
|
+
});
|
|
25
|
+
expect(onValueChange).toHaveBeenCalledWith("dark");
|
|
26
|
+
});
|
|
27
|
+
it("disabled면 클릭 토글을 막는다", () => {
|
|
28
|
+
const onValueChange = vi.fn();
|
|
29
|
+
const { result } = renderHook(() => useModeToggle({ disabled: true, onValueChange }));
|
|
30
|
+
const event = {
|
|
31
|
+
defaultPrevented: false,
|
|
32
|
+
preventDefault: vi.fn(),
|
|
33
|
+
stopPropagation: vi.fn(),
|
|
34
|
+
};
|
|
35
|
+
act(() => {
|
|
36
|
+
result.current.buttonProps.onClick?.(event);
|
|
37
|
+
});
|
|
38
|
+
expect(onValueChange).not.toHaveBeenCalled();
|
|
39
|
+
expect(event.preventDefault).toHaveBeenCalledTimes(1);
|
|
40
|
+
expect(event.stopPropagation).toHaveBeenCalledTimes(1);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-setup.d.ts","sourceRoot":"","sources":["../src/test-setup.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTextField.test.d.ts","sourceRoot":"","sources":["../../src/text-field/useTextField.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { act, renderHook } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { useTextField } from "./useTextField";
|
|
4
|
+
describe("useTextField", () => {
|
|
5
|
+
it("password 타입은 기본적으로 inputType이 password다", () => {
|
|
6
|
+
const { result } = renderHook(() => useTextField({ type: "password" }));
|
|
7
|
+
expect(result.current.isPassword).toBe(true);
|
|
8
|
+
expect(result.current.isPasswordVisible).toBe(false);
|
|
9
|
+
expect(result.current.inputType).toBe("password");
|
|
10
|
+
});
|
|
11
|
+
it("togglePasswordVisible 호출 시 가시성이 전환된다", () => {
|
|
12
|
+
const { result } = renderHook(() => useTextField({ type: "password" }));
|
|
13
|
+
act(() => {
|
|
14
|
+
result.current.togglePasswordVisible();
|
|
15
|
+
});
|
|
16
|
+
expect(result.current.inputType).toBe("text");
|
|
17
|
+
act(() => {
|
|
18
|
+
result.current.togglePasswordVisible();
|
|
19
|
+
});
|
|
20
|
+
expect(result.current.inputType).toBe("password");
|
|
21
|
+
});
|
|
22
|
+
it("disabled이면 비밀번호 가시성 토글을 막는다", () => {
|
|
23
|
+
const onPasswordVisibleChange = vi.fn();
|
|
24
|
+
const { result } = renderHook(() => useTextField({
|
|
25
|
+
type: "password",
|
|
26
|
+
disabled: true,
|
|
27
|
+
onPasswordVisibleChange,
|
|
28
|
+
}));
|
|
29
|
+
act(() => {
|
|
30
|
+
result.current.togglePasswordVisible();
|
|
31
|
+
});
|
|
32
|
+
expect(result.current.isPasswordVisible).toBe(false);
|
|
33
|
+
expect(onPasswordVisibleChange).not.toHaveBeenCalled();
|
|
34
|
+
});
|
|
35
|
+
it("password가 아닌 타입은 토글해도 타입이 바뀌지 않는다", () => {
|
|
36
|
+
const { result } = renderHook(() => useTextField({ type: "email" }));
|
|
37
|
+
act(() => {
|
|
38
|
+
result.current.togglePasswordVisible();
|
|
39
|
+
});
|
|
40
|
+
expect(result.current.isPassword).toBe(false);
|
|
41
|
+
expect(result.current.inputType).toBe("email");
|
|
42
|
+
});
|
|
43
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gbgr/react-headless",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
],
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
11
12
|
"import": "./dist/index.js",
|
|
12
|
-
"require": "./dist/index.js"
|
|
13
|
-
"default": "./dist/index.js",
|
|
14
|
-
"types": "./dist/index.d.ts"
|
|
13
|
+
"require": "./dist/index.js"
|
|
15
14
|
},
|
|
16
15
|
"./*": "./dist/*"
|
|
17
16
|
},
|
|
@@ -32,6 +31,8 @@
|
|
|
32
31
|
"scripts": {
|
|
33
32
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc -b tsconfig.json --force",
|
|
34
33
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest",
|
|
35
36
|
"clean": "rm -rf dist tsconfig.tsbuildinfo && find src -type f \\( -name '*.js' -o -name '*.js.map' -o -name '*.d.ts' -o -name '*.d.ts.map' \\) -delete"
|
|
36
37
|
}
|
|
37
38
|
}
|