@cp949/japanpost-react 1.0.4 → 1.0.5

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/client.d.ts CHANGED
@@ -1,6 +1,42 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ReactNode, ComponentPropsWithoutRef } from 'react';
3
3
 
4
+ /**
5
+ * 스타일 의존성이 없는 최소한의 주소 키워드 검색 입력 컴포넌트.
6
+ * value를 전달하면 제어 모드, 전달하지 않으면 비제어 모드로 동작한다.
7
+ * 검색 시 trim 처리를 내부에서 수행해 공백만 다른 입력이 별도 쿼리로 번지지 않게 한다.
8
+ */
9
+ declare const AddressSearchInput: react.ForwardRefExoticComponent<{
10
+ defaultValue?: string;
11
+ value?: string;
12
+ disabled?: boolean;
13
+ label?: react.ReactNode;
14
+ buttonLabel?: react.ReactNode;
15
+ inputProps?: Omit<react.ComponentPropsWithoutRef<"input">, "defaultValue" | "disabled" | "onChange" | "value">;
16
+ buttonProps?: Omit<react.ComponentPropsWithoutRef<"button">, "children" | "disabled" | "onClick" | "type">;
17
+ } & {
18
+ onChange?: (query: string) => void;
19
+ onSearch: (query: string) => void;
20
+ } & react.RefAttributes<HTMLInputElement>>;
21
+
22
+ /**
23
+ * 스타일 의존성이 없는 최소한의 우편번호 입력 컴포넌트.
24
+ * value를 전달하면 제어 모드, 전달하지 않으면 비제어 모드로 동작한다.
25
+ * 제출 시에는 표시 형식이 아니라 정규화된 숫자 문자열을 콜백에 넘기는 것이 핵심 계약이다.
26
+ */
27
+ declare const PostalCodeInput: react.ForwardRefExoticComponent<{
28
+ defaultValue?: string;
29
+ value?: string;
30
+ disabled?: boolean;
31
+ label?: react.ReactNode;
32
+ buttonLabel?: react.ReactNode;
33
+ inputProps?: Omit<react.ComponentPropsWithoutRef<"input">, "defaultValue" | "disabled" | "onChange" | "value">;
34
+ buttonProps?: Omit<react.ComponentPropsWithoutRef<"button">, "children" | "disabled" | "onClick" | "type">;
35
+ } & {
36
+ onChange?: (postalCode: string) => void;
37
+ onSearch: (postalCode: string) => void;
38
+ } & react.RefAttributes<HTMLInputElement>>;
39
+
4
40
  /**
5
41
  * `japanpost-react`의 공개 계약과 내부 정규화 계약을 한 곳에 모아 둔 타입 모음이다.
6
42
  * 훅, 입력 컴포넌트, data source, minimal-api 연동 예제가 모두 이 정의를 기준으로 맞물리므로
@@ -260,20 +296,6 @@ type AddressSearchInputProps = BaseTextSearchInputProps & {
260
296
  onSearch: (query: string) => void;
261
297
  };
262
298
 
263
- /**
264
- * 스타일 의존성이 없는 최소한의 주소 키워드 검색 입력 컴포넌트.
265
- * value를 전달하면 제어 모드, 전달하지 않으면 비제어 모드로 동작한다.
266
- * 검색 시 trim 처리를 내부에서 수행해 공백만 다른 입력이 별도 쿼리로 번지지 않게 한다.
267
- */
268
- declare function AddressSearchInput({ defaultValue, value, disabled, label, buttonLabel, inputProps, buttonProps, onChange, onSearch, }: AddressSearchInputProps): react_jsx_runtime.JSX.Element;
269
-
270
- /**
271
- * 스타일 의존성이 없는 최소한의 우편번호 입력 컴포넌트.
272
- * value를 전달하면 제어 모드, 전달하지 않으면 비제어 모드로 동작한다.
273
- * 제출 시에는 표시 형식이 아니라 정규화된 숫자 문자열을 콜백에 넘기는 것이 핵심 계약이다.
274
- */
275
- declare function PostalCodeInput({ defaultValue, value, disabled, label, buttonLabel, inputProps, buttonProps, onChange, onSearch, }: PostalCodeInputProps): react_jsx_runtime.JSX.Element;
276
-
277
299
  /**
278
300
  * 우편번호 조회와 키워드 주소 검색을 하나의 인터페이스로 제공하는 통합 훅.
279
301
  * 두 검색 모드가 공유하는 data source를 내부에서 재사용하고,
package/dist/client.es.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use client";
2
- import { useState, useMemo, useRef, useCallback, useEffect } from 'react';
2
+ import { forwardRef, useState, useMemo, useRef, useCallback, useEffect } from 'react';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
 
5
5
  // src/components/AddressSearchInput.tsx
6
- function AddressSearchInput({
6
+ var AddressSearchInput = forwardRef(function AddressSearchInput2({
7
7
  defaultValue = "",
8
8
  value,
9
9
  disabled,
@@ -13,7 +13,7 @@ function AddressSearchInput({
13
13
  buttonProps,
14
14
  onChange,
15
15
  onSearch
16
- }) {
16
+ }, ref) {
17
17
  const [internalValue, setInternalValue] = useState(defaultValue);
18
18
  const currentValue = value ?? internalValue;
19
19
  function handleSubmit(event) {
@@ -33,6 +33,7 @@ function AddressSearchInput({
33
33
  "input",
34
34
  {
35
35
  ...inputProps,
36
+ ref,
36
37
  disabled,
37
38
  value: currentValue,
38
39
  onChange: (event) => handleChange(event.target.value)
@@ -41,52 +42,55 @@ function AddressSearchInput({
41
42
  ] }),
42
43
  /* @__PURE__ */ jsx("button", { ...buttonProps, disabled, type: "submit", children: buttonLabel })
43
44
  ] });
44
- }
45
+ });
45
46
 
46
47
  // src/core/formatters.ts
47
48
  function normalizeJapanPostalCode(value) {
48
49
  return value.replace(/[^\d]/g, "");
49
50
  }
50
- function PostalCodeInput({
51
- defaultValue = "",
52
- value,
53
- disabled,
54
- label = "Postal code",
55
- buttonLabel = "Search",
56
- inputProps,
57
- buttonProps,
58
- onChange,
59
- onSearch
60
- }) {
61
- const [internalValue, setInternalValue] = useState(defaultValue);
62
- const currentValue = value ?? internalValue;
63
- function handleSubmit(event) {
64
- event.preventDefault();
65
- onSearch(normalizeJapanPostalCode(currentValue));
66
- }
67
- function handleChange(nextValue) {
68
- if (value === void 0) {
69
- setInternalValue(nextValue);
51
+ var PostalCodeInput = forwardRef(
52
+ function PostalCodeInput2({
53
+ defaultValue = "",
54
+ value,
55
+ disabled,
56
+ label = "Postal code",
57
+ buttonLabel = "Search",
58
+ inputProps,
59
+ buttonProps,
60
+ onChange,
61
+ onSearch
62
+ }, ref) {
63
+ const [internalValue, setInternalValue] = useState(defaultValue);
64
+ const currentValue = value ?? internalValue;
65
+ function handleSubmit(event) {
66
+ event.preventDefault();
67
+ onSearch(normalizeJapanPostalCode(currentValue));
70
68
  }
71
- onChange?.(nextValue);
69
+ function handleChange(nextValue) {
70
+ if (value === void 0) {
71
+ setInternalValue(nextValue);
72
+ }
73
+ onChange?.(nextValue);
74
+ }
75
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
76
+ /* @__PURE__ */ jsxs("label", { children: [
77
+ label,
78
+ /* @__PURE__ */ jsx(
79
+ "input",
80
+ {
81
+ ...inputProps,
82
+ ref,
83
+ disabled,
84
+ inputMode: inputProps?.inputMode ?? "numeric",
85
+ value: currentValue,
86
+ onChange: (event) => handleChange(event.target.value)
87
+ }
88
+ )
89
+ ] }),
90
+ /* @__PURE__ */ jsx("button", { ...buttonProps, disabled, type: "submit", children: buttonLabel })
91
+ ] });
72
92
  }
73
- return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
74
- /* @__PURE__ */ jsxs("label", { children: [
75
- label,
76
- /* @__PURE__ */ jsx(
77
- "input",
78
- {
79
- ...inputProps,
80
- disabled,
81
- inputMode: inputProps?.inputMode ?? "numeric",
82
- value: currentValue,
83
- onChange: (event) => handleChange(event.target.value)
84
- }
85
- )
86
- ] }),
87
- /* @__PURE__ */ jsx("button", { ...buttonProps, disabled, type: "submit", children: buttonLabel })
88
- ] });
89
- }
93
+ );
90
94
 
91
95
  // src/core/errors.ts
92
96
  function createJapanAddressError(code, message, options) {
@@ -99,8 +103,24 @@ function createJapanAddressError(code, message, options) {
99
103
  }
100
104
 
101
105
  // src/react/toJapanAddressError.ts
106
+ var JAPAN_ADDRESS_ERROR_CODES = /* @__PURE__ */ new Set([
107
+ "invalid_postal_code",
108
+ "invalid_query",
109
+ "network_error",
110
+ "timeout",
111
+ "not_found",
112
+ "bad_response",
113
+ "data_source_error"
114
+ ]);
115
+ function isJapanAddressError(error) {
116
+ if (typeof error !== "object" || error === null) {
117
+ return false;
118
+ }
119
+ const maybeError = error;
120
+ return maybeError.name === "JapanAddressError" && typeof maybeError.code === "string" && JAPAN_ADDRESS_ERROR_CODES.has(maybeError.code);
121
+ }
102
122
  function toJapanAddressError(error) {
103
- if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string") {
123
+ if (isJapanAddressError(error)) {
104
124
  return error;
105
125
  }
106
126
  return createJapanAddressError(
package/dist/index.d.ts CHANGED
@@ -1,6 +1,42 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ReactNode, ComponentPropsWithoutRef } from 'react';
3
3
 
4
+ /**
5
+ * 스타일 의존성이 없는 최소한의 주소 키워드 검색 입력 컴포넌트.
6
+ * value를 전달하면 제어 모드, 전달하지 않으면 비제어 모드로 동작한다.
7
+ * 검색 시 trim 처리를 내부에서 수행해 공백만 다른 입력이 별도 쿼리로 번지지 않게 한다.
8
+ */
9
+ declare const AddressSearchInput: react.ForwardRefExoticComponent<{
10
+ defaultValue?: string;
11
+ value?: string;
12
+ disabled?: boolean;
13
+ label?: react.ReactNode;
14
+ buttonLabel?: react.ReactNode;
15
+ inputProps?: Omit<react.ComponentPropsWithoutRef<"input">, "defaultValue" | "disabled" | "onChange" | "value">;
16
+ buttonProps?: Omit<react.ComponentPropsWithoutRef<"button">, "children" | "disabled" | "onClick" | "type">;
17
+ } & {
18
+ onChange?: (query: string) => void;
19
+ onSearch: (query: string) => void;
20
+ } & react.RefAttributes<HTMLInputElement>>;
21
+
22
+ /**
23
+ * 스타일 의존성이 없는 최소한의 우편번호 입력 컴포넌트.
24
+ * value를 전달하면 제어 모드, 전달하지 않으면 비제어 모드로 동작한다.
25
+ * 제출 시에는 표시 형식이 아니라 정규화된 숫자 문자열을 콜백에 넘기는 것이 핵심 계약이다.
26
+ */
27
+ declare const PostalCodeInput: react.ForwardRefExoticComponent<{
28
+ defaultValue?: string;
29
+ value?: string;
30
+ disabled?: boolean;
31
+ label?: react.ReactNode;
32
+ buttonLabel?: react.ReactNode;
33
+ inputProps?: Omit<react.ComponentPropsWithoutRef<"input">, "defaultValue" | "disabled" | "onChange" | "value">;
34
+ buttonProps?: Omit<react.ComponentPropsWithoutRef<"button">, "children" | "disabled" | "onClick" | "type">;
35
+ } & {
36
+ onChange?: (postalCode: string) => void;
37
+ onSearch: (postalCode: string) => void;
38
+ } & react.RefAttributes<HTMLInputElement>>;
39
+
4
40
  /**
5
41
  * minimal-api가 그대로 받는 공개 searchcode 요청 타입이다.
6
42
  * pageNumber/rowsPerPage를 노출하는 이유는 라이브러리와 API 예제가 같은 pager 의미 체계를 공유하기 위해서다.
@@ -221,20 +257,6 @@ type AddressSearchInputProps = BaseTextSearchInputProps & {
221
257
  onSearch: (query: string) => void;
222
258
  };
223
259
 
224
- /**
225
- * 스타일 의존성이 없는 최소한의 주소 키워드 검색 입력 컴포넌트.
226
- * value를 전달하면 제어 모드, 전달하지 않으면 비제어 모드로 동작한다.
227
- * 검색 시 trim 처리를 내부에서 수행해 공백만 다른 입력이 별도 쿼리로 번지지 않게 한다.
228
- */
229
- declare function AddressSearchInput({ defaultValue, value, disabled, label, buttonLabel, inputProps, buttonProps, onChange, onSearch, }: AddressSearchInputProps): react_jsx_runtime.JSX.Element;
230
-
231
- /**
232
- * 스타일 의존성이 없는 최소한의 우편번호 입력 컴포넌트.
233
- * value를 전달하면 제어 모드, 전달하지 않으면 비제어 모드로 동작한다.
234
- * 제출 시에는 표시 형식이 아니라 정규화된 숫자 문자열을 콜백에 넘기는 것이 핵심 계약이다.
235
- */
236
- declare function PostalCodeInput({ defaultValue, value, disabled, label, buttonLabel, inputProps, buttonProps, onChange, onSearch, }: PostalCodeInputProps): react_jsx_runtime.JSX.Element;
237
-
238
260
  /**
239
261
  * 라이브러리 전반에서 공통으로 쓰는 오류 객체 생성기다.
240
262
  * 브라우저 fetch 오류, validation 오류, data source 오류를 모두 같은 표면으로 맞춰
package/dist/index.es.js CHANGED
@@ -1,8 +1,8 @@
1
- import { useState, useMemo, useRef, useCallback, useEffect } from 'react';
1
+ import { forwardRef, useState, useMemo, useRef, useCallback, useEffect } from 'react';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
 
4
4
  // src/components/AddressSearchInput.tsx
5
- function AddressSearchInput({
5
+ var AddressSearchInput = forwardRef(function AddressSearchInput2({
6
6
  defaultValue = "",
7
7
  value,
8
8
  disabled,
@@ -12,7 +12,7 @@ function AddressSearchInput({
12
12
  buttonProps,
13
13
  onChange,
14
14
  onSearch
15
- }) {
15
+ }, ref) {
16
16
  const [internalValue, setInternalValue] = useState(defaultValue);
17
17
  const currentValue = value ?? internalValue;
18
18
  function handleSubmit(event) {
@@ -32,6 +32,7 @@ function AddressSearchInput({
32
32
  "input",
33
33
  {
34
34
  ...inputProps,
35
+ ref,
35
36
  disabled,
36
37
  value: currentValue,
37
38
  onChange: (event) => handleChange(event.target.value)
@@ -40,7 +41,7 @@ function AddressSearchInput({
40
41
  ] }),
41
42
  /* @__PURE__ */ jsx("button", { ...buttonProps, disabled, type: "submit", children: buttonLabel })
42
43
  ] });
43
- }
44
+ });
44
45
 
45
46
  // src/core/formatters.ts
46
47
  function normalizeJapanPostalCode(value) {
@@ -53,46 +54,49 @@ function formatJapanPostalCode(value) {
53
54
  }
54
55
  return `${normalized.slice(0, 3)}-${normalized.slice(3)}`;
55
56
  }
56
- function PostalCodeInput({
57
- defaultValue = "",
58
- value,
59
- disabled,
60
- label = "Postal code",
61
- buttonLabel = "Search",
62
- inputProps,
63
- buttonProps,
64
- onChange,
65
- onSearch
66
- }) {
67
- const [internalValue, setInternalValue] = useState(defaultValue);
68
- const currentValue = value ?? internalValue;
69
- function handleSubmit(event) {
70
- event.preventDefault();
71
- onSearch(normalizeJapanPostalCode(currentValue));
72
- }
73
- function handleChange(nextValue) {
74
- if (value === void 0) {
75
- setInternalValue(nextValue);
57
+ var PostalCodeInput = forwardRef(
58
+ function PostalCodeInput2({
59
+ defaultValue = "",
60
+ value,
61
+ disabled,
62
+ label = "Postal code",
63
+ buttonLabel = "Search",
64
+ inputProps,
65
+ buttonProps,
66
+ onChange,
67
+ onSearch
68
+ }, ref) {
69
+ const [internalValue, setInternalValue] = useState(defaultValue);
70
+ const currentValue = value ?? internalValue;
71
+ function handleSubmit(event) {
72
+ event.preventDefault();
73
+ onSearch(normalizeJapanPostalCode(currentValue));
76
74
  }
77
- onChange?.(nextValue);
75
+ function handleChange(nextValue) {
76
+ if (value === void 0) {
77
+ setInternalValue(nextValue);
78
+ }
79
+ onChange?.(nextValue);
80
+ }
81
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
82
+ /* @__PURE__ */ jsxs("label", { children: [
83
+ label,
84
+ /* @__PURE__ */ jsx(
85
+ "input",
86
+ {
87
+ ...inputProps,
88
+ ref,
89
+ disabled,
90
+ inputMode: inputProps?.inputMode ?? "numeric",
91
+ value: currentValue,
92
+ onChange: (event) => handleChange(event.target.value)
93
+ }
94
+ )
95
+ ] }),
96
+ /* @__PURE__ */ jsx("button", { ...buttonProps, disabled, type: "submit", children: buttonLabel })
97
+ ] });
78
98
  }
79
- return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
80
- /* @__PURE__ */ jsxs("label", { children: [
81
- label,
82
- /* @__PURE__ */ jsx(
83
- "input",
84
- {
85
- ...inputProps,
86
- disabled,
87
- inputMode: inputProps?.inputMode ?? "numeric",
88
- value: currentValue,
89
- onChange: (event) => handleChange(event.target.value)
90
- }
91
- )
92
- ] }),
93
- /* @__PURE__ */ jsx("button", { ...buttonProps, disabled, type: "submit", children: buttonLabel })
94
- ] });
95
- }
99
+ );
96
100
 
97
101
  // src/core/errors.ts
98
102
  function createJapanAddressError(code, message, options) {
@@ -134,8 +138,24 @@ function isValidJapanPostalCode(value) {
134
138
  }
135
139
 
136
140
  // src/react/toJapanAddressError.ts
141
+ var JAPAN_ADDRESS_ERROR_CODES = /* @__PURE__ */ new Set([
142
+ "invalid_postal_code",
143
+ "invalid_query",
144
+ "network_error",
145
+ "timeout",
146
+ "not_found",
147
+ "bad_response",
148
+ "data_source_error"
149
+ ]);
150
+ function isJapanAddressError(error) {
151
+ if (typeof error !== "object" || error === null) {
152
+ return false;
153
+ }
154
+ const maybeError = error;
155
+ return maybeError.name === "JapanAddressError" && typeof maybeError.code === "string" && JAPAN_ADDRESS_ERROR_CODES.has(maybeError.code);
156
+ }
137
157
  function toJapanAddressError(error) {
138
- if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string") {
158
+ if (isJapanAddressError(error)) {
139
159
  return error;
140
160
  }
141
161
  return createJapanAddressError(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cp949/japanpost-react",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Headless React hooks and optional components for Japan Post postcode and address search",
5
5
  "type": "module",
6
6
  "author": "cp949",
@@ -66,7 +66,7 @@
66
66
  "scripts": {
67
67
  "dev": "tsup --config tsup.config.ts --watch",
68
68
  "build": "tsup --config tsup.config.ts && node scripts/postbuild-client.mjs",
69
- "release": "pnpm --dir ../.. readme:package && pnpm --dir ../.. test && pnpm build && pnpm publish --access public --no-git-checks",
69
+ "release": "pnpm --dir ../.. readme:package && pnpm --dir ../.. test && pnpm build && pnpm publish --access public",
70
70
  "lint": "biome lint .",
71
71
  "check-types": "tsc --noEmit",
72
72
  "test": "pnpm test:unit",