slick-address-kr 1.0.4 → 2.0.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/CHANGELOG.md +153 -0
- package/README.ko.md +36 -7
- package/README.md +228 -98
- package/dist/address-finder-sdLnl5hT.d.cts +243 -0
- package/dist/address-finder-sdLnl5hT.d.ts +243 -0
- package/dist/browser.global.js +65 -0
- package/dist/browser.global.js.map +1 -0
- package/dist/chunk-H7AKAKT3.js +574 -0
- package/dist/chunk-H7AKAKT3.js.map +1 -0
- package/dist/index.cjs +607 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +50 -0
- package/dist/index.d.ts +48 -6
- package/dist/index.js +20 -8
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +639 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +26 -0
- package/dist/react/index.d.ts +26 -0
- package/dist/react/index.js +51 -0
- package/dist/react/index.js.map +1 -0
- package/dist/styles.css +79 -34
- package/dist/vue/index.cjs +627 -0
- package/dist/vue/index.cjs.map +1 -0
- package/dist/vue/index.d.cts +23 -0
- package/dist/vue/index.d.ts +23 -0
- package/dist/vue/index.js +40 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +88 -18
- package/API-KEY-GUIDE.md +0 -428
- package/AUTOCOMPLETE-GUIDE.md +0 -399
- package/HOW-TO-USE.md +0 -416
- package/config.example.js +0 -16
- package/dist/address-finder.d.ts +0 -72
- package/dist/address-finder.js +0 -273
- package/dist/api-client.d.ts +0 -25
- package/dist/api-client.js +0 -84
- package/dist/types.d.ts +0 -83
- package/dist/types.js +0 -1
- package/index.html +0 -85
- package/korean-address-finder.js +0 -378
package/README.md
CHANGED
|
@@ -7,16 +7,21 @@ Korean address search library using official road address API - No popup require
|
|
|
7
7
|
[](https://www.npmjs.com/package/slick-address-kr)
|
|
8
8
|
[](https://github.com/Devguru-J/slick-address-kr/blob/main/LICENSE)
|
|
9
9
|
|
|
10
|
+
> v1에서 올라오는 경우 [docs/MIGRATION-v2.md](./docs/MIGRATION-v2.md)를 먼저 읽으세요.
|
|
11
|
+
|
|
10
12
|
## 특징
|
|
11
13
|
|
|
12
14
|
- ✨ **팝업 없는 인라인 UI**: 다음 주소 API처럼 새 창이 열리지 않습니다
|
|
13
15
|
- 🚀 **가벼운 용량**: 외부 의존성 없이 순수 TypeScript로 작성
|
|
14
16
|
- 📱 **반응형 디자인**: 모바일부터 데스크톱까지 완벽 지원
|
|
15
|
-
- 🎨 **커스터마이징 가능**: CSS
|
|
17
|
+
- 🎨 **커스터마이징 가능**: CSS 변수와 클래스로 쉽게 스타일 변경 가능
|
|
18
|
+
- 🌗 **다크모드 지원**: `--kaf-*` CSS 변수와 `prefers-color-scheme` 대응
|
|
16
19
|
- ⚡ **자동완성 모드**: 타이핑하는 즉시 검색 결과 표시
|
|
17
20
|
- ⌨️ **키보드 네비게이션**: 화살표 키로 결과 선택, 엔터로 적용 - 마우스 없이 빠른 입력!
|
|
21
|
+
- ♿ **스크린리더 지원**: ARIA combobox 패턴 적용
|
|
18
22
|
- 🔒 **TypeScript 지원**: 완전한 타입 정의 제공
|
|
19
|
-
- 🌐 **프레임워크 무관**: Vanilla JS
|
|
23
|
+
- 🌐 **프레임워크 무관**: Vanilla JS는 물론, React/Vue 전용 어댑터 제공
|
|
24
|
+
- 🔌 **자체 프록시 연동**: `endpoint`/`fetchFn` 옵션으로 API 키를 서버에 숨길 수 있음
|
|
20
25
|
- 📦 **모든 패키지 매니저 지원**: npm, yarn, pnpm, bun, deno 모두 호환
|
|
21
26
|
|
|
22
27
|
## 설치
|
|
@@ -43,21 +48,30 @@ bun add slick-address-kr
|
|
|
43
48
|
|
|
44
49
|
### deno
|
|
45
50
|
```typescript
|
|
46
|
-
import { KoreanAddressFinder } from "npm:slick-address-kr@
|
|
51
|
+
import { KoreanAddressFinder } from "npm:slick-address-kr@2";
|
|
47
52
|
```
|
|
48
53
|
|
|
54
|
+
> **TypeScript 사용자 참고:** `moduleResolution: "node"`(node10) 설정은
|
|
55
|
+
> 지원하지 않습니다. `"bundler"`, `"node16"`, `"nodenext"` 중 하나를
|
|
56
|
+
> 쓰세요 — 이 패키지는 `exports` 필드 기반 타입 해석만 제공합니다.
|
|
57
|
+
|
|
49
58
|
## 빠른 시작
|
|
50
59
|
|
|
51
60
|
### 1. 기본 사용 (Vanilla JavaScript)
|
|
52
61
|
|
|
53
62
|
**간단한 방법:**
|
|
54
63
|
|
|
55
|
-
1.
|
|
56
|
-
|
|
64
|
+
1. 라이브러리를 빌드합니다 (`examples/`는 `../dist/index.js`를 직접 참조하며,
|
|
65
|
+
`dist/`는 git에 커밋되지 않습니다):
|
|
66
|
+
```bash
|
|
67
|
+
npm run build
|
|
68
|
+
```
|
|
69
|
+
2. 프로젝트 폴더의 `examples/index.html` 파일을 참조하세요
|
|
70
|
+
3. 로컬 서버 실행:
|
|
57
71
|
```bash
|
|
58
72
|
python -m http.server 8000
|
|
59
73
|
```
|
|
60
|
-
|
|
74
|
+
4. 브라우저에서 열기:
|
|
61
75
|
```
|
|
62
76
|
http://localhost:8000/examples/
|
|
63
77
|
```
|
|
@@ -70,101 +84,107 @@ import { KoreanAddressFinder } from "npm:slick-address-kr@1.0.4";
|
|
|
70
84
|
<head>
|
|
71
85
|
<meta charset="UTF-8">
|
|
72
86
|
<title>주소 검색</title>
|
|
87
|
+
<link rel="stylesheet" href="node_modules/slick-address-kr/dist/styles.css">
|
|
73
88
|
</head>
|
|
74
89
|
<body>
|
|
75
90
|
<div id="address-search"></div>
|
|
76
91
|
|
|
77
|
-
<script
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// 검색 UI 구현...
|
|
92
|
+
<script src="node_modules/slick-address-kr/dist/browser.global.js"></script>
|
|
93
|
+
<script>
|
|
94
|
+
// 전역 이름은 window.KoreanAddressFinder다
|
|
95
|
+
const finder = new KoreanAddressFinder({
|
|
96
|
+
apiKey: 'YOUR_API_KEY',
|
|
97
|
+
autocompleteMode: true,
|
|
98
|
+
onSelect: (address, meta) => {
|
|
99
|
+
console.log(meta.reason, address);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
finder.init(document.getElementById('address-search'));
|
|
92
104
|
</script>
|
|
93
105
|
</body>
|
|
94
106
|
</html>
|
|
95
107
|
```
|
|
96
108
|
|
|
109
|
+
ESM 환경(모듈 번들러)에서는 다음처럼 씁니다.
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
import { KoreanAddressFinder } from 'slick-address-kr';
|
|
113
|
+
import 'slick-address-kr/styles.css';
|
|
114
|
+
|
|
115
|
+
const finder = new KoreanAddressFinder({
|
|
116
|
+
apiKey: 'YOUR_API_KEY',
|
|
117
|
+
onSelect: (address) => console.log(address),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
finder.init(document.getElementById('address-search'));
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
CommonJS로 `require`하는 경우, `require('slick-address-kr')`는 이름공간 객체를
|
|
124
|
+
돌려주므로 `.default`나 이름이 붙은 export를 꺼내 써야 합니다.
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
const { KoreanAddressFinder } = require('slick-address-kr');
|
|
128
|
+
// 또는
|
|
129
|
+
const KoreanAddressFinder = require('slick-address-kr').default;
|
|
130
|
+
```
|
|
131
|
+
|
|
97
132
|
### 2. React에서 사용
|
|
98
133
|
|
|
134
|
+
전용 훅을 쓰는 것을 권장합니다.
|
|
135
|
+
|
|
99
136
|
```jsx
|
|
100
|
-
import
|
|
101
|
-
import
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
finderRef.current.init(containerRef.current);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return () => {
|
|
120
|
-
if (finderRef.current) {
|
|
121
|
-
finderRef.current.destroy();
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
}, []);
|
|
125
|
-
|
|
126
|
-
return <div ref={containerRef}></div>;
|
|
137
|
+
import { useKoreanAddress } from 'slick-address-kr/react';
|
|
138
|
+
import 'slick-address-kr/styles.css';
|
|
139
|
+
|
|
140
|
+
function AddressForm() {
|
|
141
|
+
const { containerRef, address } = useKoreanAddress({
|
|
142
|
+
apiKey: import.meta.env.VITE_JUSO_API_KEY,
|
|
143
|
+
autocompleteMode: true,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<>
|
|
148
|
+
<div ref={containerRef} />
|
|
149
|
+
{address && <p>{address.zipCode} {address.roadAddress}</p>}
|
|
150
|
+
</>
|
|
151
|
+
);
|
|
127
152
|
}
|
|
128
153
|
```
|
|
129
154
|
|
|
155
|
+
훅 없이 클래스를 직접 다루고 싶다면 `examples/react-example.jsx`를 참고하세요.
|
|
156
|
+
|
|
130
157
|
### 3. Vue에서 사용
|
|
131
158
|
|
|
132
159
|
```vue
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
160
|
+
<script setup>
|
|
161
|
+
import { useKoreanAddress } from 'slick-address-kr/vue';
|
|
162
|
+
import 'slick-address-kr/styles.css';
|
|
136
163
|
|
|
137
|
-
|
|
138
|
-
import
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
export default {
|
|
142
|
-
mounted() {
|
|
143
|
-
this.finder = new KoreanAddressFinder({
|
|
144
|
-
onSelect: (address) => {
|
|
145
|
-
console.log('선택된 주소:', address);
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
this.finder.init(this.$refs.addressContainer);
|
|
150
|
-
},
|
|
151
|
-
|
|
152
|
-
beforeUnmount() {
|
|
153
|
-
if (this.finder) {
|
|
154
|
-
this.finder.destroy();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
};
|
|
164
|
+
const { containerRef, address } = useKoreanAddress({
|
|
165
|
+
apiKey: import.meta.env.VITE_JUSO_API_KEY,
|
|
166
|
+
autocompleteMode: true,
|
|
167
|
+
});
|
|
158
168
|
</script>
|
|
169
|
+
|
|
170
|
+
<template>
|
|
171
|
+
<div ref="containerRef"></div>
|
|
172
|
+
<p v-if="address">{{ address.zipCode }} {{ address.roadAddress }}</p>
|
|
173
|
+
</template>
|
|
159
174
|
```
|
|
160
175
|
|
|
176
|
+
> **참고:** `slick-address-kr/vue`의 컴포저블은 `setup()` 시점의 옵션을
|
|
177
|
+
> 한 번만 캡처합니다. React 훅과 달리 이후 `onSelect` 등을 바꿔도
|
|
178
|
+
> 반영되지 않습니다. 콜백을 동적으로 바꿔야 한다면 반환된 `finder` 인스턴스를
|
|
179
|
+
> 직접 조작하세요.
|
|
180
|
+
|
|
161
181
|
## API 문서
|
|
162
182
|
|
|
163
183
|
### Options
|
|
164
184
|
|
|
165
185
|
```typescript
|
|
166
186
|
interface AddressFinderOptions {
|
|
167
|
-
/** 행정안전부 API
|
|
187
|
+
/** 행정안전부 API 키. endpoint를 자체 프록시로 지정한 경우 생략 가능 */
|
|
168
188
|
apiKey?: string;
|
|
169
189
|
|
|
170
190
|
/** 한 페이지에 표시할 결과 수 (기본값: 10) */
|
|
@@ -173,11 +193,11 @@ interface AddressFinderOptions {
|
|
|
173
193
|
/** 현재 페이지 번호 (기본값: 1) */
|
|
174
194
|
currentPage?: number;
|
|
175
195
|
|
|
176
|
-
/** 검색 결과를 표시할 컨테이너 ID */
|
|
196
|
+
/** 검색 결과를 표시할 컨테이너 ID. init()에 엘리먼트를 직접 넘기면 무시됨 */
|
|
177
197
|
containerId?: string;
|
|
178
198
|
|
|
179
|
-
/** 주소 선택
|
|
180
|
-
onSelect?: (address: AddressResult) => void;
|
|
199
|
+
/** 주소 선택 시, 그리고 상세주소가 바뀔 때마다 호출된다 */
|
|
200
|
+
onSelect?: (address: AddressResult, meta: AddressSelectMeta) => void;
|
|
181
201
|
|
|
182
202
|
/** 상세주소 입력 필드 표시 여부 (기본값: true) */
|
|
183
203
|
showDetailInput?: boolean;
|
|
@@ -187,6 +207,12 @@ interface AddressFinderOptions {
|
|
|
187
207
|
|
|
188
208
|
/** 자동완성 모드 사용 여부 (기본값: false) */
|
|
189
209
|
autocompleteMode?: boolean;
|
|
210
|
+
|
|
211
|
+
/** 호출할 주소. 자체 프록시 서버를 쓸 때 지정 */
|
|
212
|
+
endpoint?: string;
|
|
213
|
+
|
|
214
|
+
/** fetch 대체 구현. 인증 헤더 주입이나 테스트에 사용 */
|
|
215
|
+
fetchFn?: typeof fetch;
|
|
190
216
|
}
|
|
191
217
|
```
|
|
192
218
|
|
|
@@ -220,6 +246,21 @@ interface AddressResult {
|
|
|
220
246
|
|
|
221
247
|
/** 읍면동명 */
|
|
222
248
|
bname?: string;
|
|
249
|
+
|
|
250
|
+
/** 상세주소·좌표 API 연동에 필요한 원본 코드 (행정구역코드, 도로명코드 등) */
|
|
251
|
+
codes?: AddressCodes;
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### AddressSelectMeta
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
interface AddressSelectMeta {
|
|
259
|
+
/**
|
|
260
|
+
* 'select' — 사용자가 검색 결과에서 주소를 고른 시점
|
|
261
|
+
* 'detail-change' — 상세주소 입력값이 바뀐 시점
|
|
262
|
+
*/
|
|
263
|
+
reason: 'select' | 'detail-change';
|
|
223
264
|
}
|
|
224
265
|
```
|
|
225
266
|
|
|
@@ -238,21 +279,67 @@ finder.init(document.getElementById('my-container')); // 직접 엘리먼트 전
|
|
|
238
279
|
|
|
239
280
|
#### `destroy(): void`
|
|
240
281
|
|
|
241
|
-
컴포넌트를 제거하고 이벤트 리스너를 정리합니다.
|
|
282
|
+
컴포넌트를 제거하고 이벤트 리스너를 정리합니다. 여러 번 호출해도 안전합니다.
|
|
242
283
|
|
|
243
284
|
```javascript
|
|
244
285
|
finder.destroy();
|
|
245
286
|
```
|
|
246
287
|
|
|
247
|
-
#### `getSelectedAddress():
|
|
288
|
+
#### `getSelectedAddress(): AddressResult | null`
|
|
248
289
|
|
|
249
|
-
현재 선택된 주소 정보를 반환합니다.
|
|
290
|
+
현재 선택된 주소 정보를 반환합니다. 선택 전에는 `null`입니다.
|
|
250
291
|
|
|
251
292
|
```javascript
|
|
252
293
|
const selected = finder.getSelectedAddress();
|
|
253
|
-
console.log(selected); //
|
|
294
|
+
console.log(selected); // AddressResult | null
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### `search(): Promise<void>`
|
|
298
|
+
|
|
299
|
+
검색 입력란의 현재 값으로 주소를 검색합니다. 검색 버튼 클릭이나 Enter와
|
|
300
|
+
같은 동작을 코드에서 그대로 재현할 때 씁니다. 진행 중이던 이전 검색은
|
|
301
|
+
자동으로 취소됩니다.
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
await finder.search();
|
|
254
305
|
```
|
|
255
306
|
|
|
307
|
+
### 에러 처리
|
|
308
|
+
|
|
309
|
+
API 호출이 실패하면 `JusoApiError`가 던져집니다 (v1처럼 조용히 빈 결과로
|
|
310
|
+
처리되지 않습니다). `AddressApiClient`를 직접 쓰는 경우:
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
import { AddressApiClient, JusoApiError } from 'slick-address-kr';
|
|
314
|
+
|
|
315
|
+
const client = new AddressApiClient({ apiKey: 'YOUR_API_KEY' });
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
const { results, totalCount } = await client.search('판교역로 235', {
|
|
319
|
+
currentPage: 1,
|
|
320
|
+
countPerPage: 10,
|
|
321
|
+
});
|
|
322
|
+
} catch (error) {
|
|
323
|
+
if (error instanceof JusoApiError) {
|
|
324
|
+
// error.code: 행안부 API 원본 에러 코드
|
|
325
|
+
// error.userMessage: 화면에 바로 보여줄 수 있는 한국어 안내
|
|
326
|
+
console.error(error.code, error.userMessage);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
`error.userMessage`는 실제 API로 확인된 코드에만 따로 쓴 안내를 담습니다.
|
|
332
|
+
|
|
333
|
+
- 승인키 문제(`E0001`): 키·도메인 확인 안내와 발급 링크
|
|
334
|
+
- 검색어 문제(`E0005` 빈 검색어, `E0006` 시도명만 입력, `E0008` 한 글자,
|
|
335
|
+
`E0009`·`E0012` 숫자·특수문자만, `E0013` 금지 특수문자): 코드 번호 없는
|
|
336
|
+
부드러운 안내. `error.isInputError`가 `true`이고, 컴포넌트는 빨간 오류 대신
|
|
337
|
+
결과 머리줄 한 줄로 보여줍니다.
|
|
338
|
+
|
|
339
|
+
그 외 코드는 API가 준 원본 메시지를 그대로 담습니다.
|
|
340
|
+
|
|
341
|
+
자동완성 모드는 검색어가 두 글자가 될 때까지 검색하지 않습니다.
|
|
342
|
+
|
|
256
343
|
## 사용 예제
|
|
257
344
|
|
|
258
345
|
### 자동완성 모드
|
|
@@ -261,6 +348,7 @@ console.log(selected); // { roadAddress, zipCode, detailAddress }
|
|
|
261
348
|
|
|
262
349
|
```javascript
|
|
263
350
|
const finder = new KoreanAddressFinder({
|
|
351
|
+
apiKey: 'YOUR_API_KEY',
|
|
264
352
|
autocompleteMode: true,
|
|
265
353
|
onSelect: (address) => {
|
|
266
354
|
console.log(address);
|
|
@@ -270,22 +358,21 @@ const finder = new KoreanAddressFinder({
|
|
|
270
358
|
finder.init();
|
|
271
359
|
```
|
|
272
360
|
|
|
273
|
-
### 키보드 네비게이션
|
|
361
|
+
### 키보드 네비게이션
|
|
274
362
|
|
|
275
363
|
마우스 없이 키보드만으로 주소를 빠르게 입력할 수 있습니다!
|
|
276
364
|
|
|
277
365
|
**사용 방법:**
|
|
278
|
-
- **⬇️ 화살표
|
|
279
|
-
-
|
|
280
|
-
- **Enter**: 선택된 주소를 폼에 적용
|
|
366
|
+
- **⬇️ 화살표 아래 / ⬆️ 화살표 위**: 검색 결과 사이를 순환 이동
|
|
367
|
+
- **Enter**: 활성화된 결과를 선택 (없으면 검색 실행)
|
|
281
368
|
- **ESC**: 검색 결과 닫기
|
|
282
369
|
|
|
283
370
|
```javascript
|
|
284
|
-
//
|
|
371
|
+
// 검색 결과가 열려 있으면 키보드 네비게이션이 자동으로 활성화됩니다
|
|
285
372
|
const finder = new KoreanAddressFinder({
|
|
286
373
|
autocompleteMode: true, // 타이핑 시 자동 검색
|
|
287
|
-
onSelect: (address) => {
|
|
288
|
-
console.log('선택된 주소:', address);
|
|
374
|
+
onSelect: (address, meta) => {
|
|
375
|
+
console.log('선택된 주소:', address, meta.reason);
|
|
289
376
|
// 폼에 자동으로 입력됩니다
|
|
290
377
|
}
|
|
291
378
|
});
|
|
@@ -299,6 +386,7 @@ finder.init();
|
|
|
299
386
|
|
|
300
387
|
```javascript
|
|
301
388
|
const finder = new KoreanAddressFinder({
|
|
389
|
+
apiKey: 'YOUR_API_KEY',
|
|
302
390
|
showDetailInput: false,
|
|
303
391
|
onSelect: (address) => {
|
|
304
392
|
console.log(address);
|
|
@@ -308,10 +396,37 @@ const finder = new KoreanAddressFinder({
|
|
|
308
396
|
finder.init();
|
|
309
397
|
```
|
|
310
398
|
|
|
311
|
-
###
|
|
399
|
+
### 자체 프록시 서버로 승인키 숨기기
|
|
400
|
+
|
|
401
|
+
API 키를 클라이언트 번들에 노출하고 싶지 않다면, 자체 서버가 승인키를
|
|
402
|
+
붙여 행안부 API를 대신 호출하게 하고 `endpoint`만 지정하세요.
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
new KoreanAddressFinder({
|
|
406
|
+
endpoint: 'https://your-server.example/api/address',
|
|
407
|
+
// apiKey는 서버가 붙이므로 전달하지 않습니다
|
|
408
|
+
});
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
동작하는 예제 서버는 `examples/backend-proxy/`에 있습니다.
|
|
412
|
+
|
|
413
|
+
### 테마 커스터마이징
|
|
414
|
+
|
|
415
|
+
색상은 CSS 변수로 바꿀 수 있습니다.
|
|
416
|
+
|
|
417
|
+
```css
|
|
418
|
+
.kaf-wrapper {
|
|
419
|
+
--kaf-accent: #ff6b35;
|
|
420
|
+
--kaf-border: #ddd;
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
다크모드는 `prefers-color-scheme: dark`를 자동으로 따릅니다. 클래스 단위
|
|
425
|
+
커스터마이징이 필요하면 `customClass` 옵션을 쓰세요.
|
|
312
426
|
|
|
313
427
|
```javascript
|
|
314
428
|
const finder = new KoreanAddressFinder({
|
|
429
|
+
apiKey: 'YOUR_API_KEY',
|
|
315
430
|
customClass: 'my-custom-class',
|
|
316
431
|
onSelect: (address) => {
|
|
317
432
|
console.log(address);
|
|
@@ -337,10 +452,12 @@ finder.init();
|
|
|
337
452
|
|
|
338
453
|
### 1. API 키 발급
|
|
339
454
|
|
|
340
|
-
1. [주소기반산업지원서비스](https://business.juso.go.kr/) 접속
|
|
455
|
+
1. [주소기반산업지원서비스 검색 API 신청](https://business.juso.go.kr/jst/jstAddressApiApplicationWrite) 접속
|
|
341
456
|
2. 승인키 신청
|
|
342
457
|
3. ⚠️ **중요: "검색 API" 선택** (팝업 API가 아님!)
|
|
343
|
-
4.
|
|
458
|
+
4. **사용할 도메인을 등록하세요.** 발급 시 등록한 도메인에서만 호출이
|
|
459
|
+
허용됩니다. **localhost 개발에는 도메인에 `localhost`를 넣은 별도의
|
|
460
|
+
개발용 키가 필요합니다.**
|
|
344
461
|
|
|
345
462
|
### 2. API 키 안전하게 사용하기
|
|
346
463
|
|
|
@@ -369,12 +486,12 @@ const finder = new KoreanAddressFinder({
|
|
|
369
486
|
|
|
370
487
|
```bash
|
|
371
488
|
# .env
|
|
372
|
-
|
|
489
|
+
VITE_JUSO_API_KEY=your_key_here
|
|
373
490
|
```
|
|
374
491
|
|
|
375
492
|
```javascript
|
|
376
493
|
const finder = new KoreanAddressFinder({
|
|
377
|
-
apiKey:
|
|
494
|
+
apiKey: import.meta.env.VITE_JUSO_API_KEY,
|
|
378
495
|
onSelect: (address) => console.log(address)
|
|
379
496
|
});
|
|
380
497
|
```
|
|
@@ -386,12 +503,13 @@ API 키를 서버에만 저장하고 클라이언트는 자체 서버를 통해
|
|
|
386
503
|
```javascript
|
|
387
504
|
// 클라이언트에서는 apiKey 불필요
|
|
388
505
|
const finder = new KoreanAddressFinder({
|
|
389
|
-
|
|
506
|
+
endpoint: 'https://your-server.example/api/address',
|
|
390
507
|
onSelect: (address) => console.log(address)
|
|
391
508
|
});
|
|
392
509
|
```
|
|
393
510
|
|
|
394
|
-
자세한 내용은
|
|
511
|
+
자세한 내용은 [docs/API-KEY-GUIDE.md](./docs/API-KEY-GUIDE.md) 및
|
|
512
|
+
`examples/backend-proxy/` 참조
|
|
395
513
|
|
|
396
514
|
## 다음 주소 API와의 비교
|
|
397
515
|
|
|
@@ -414,13 +532,25 @@ const finder = new KoreanAddressFinder({
|
|
|
414
532
|
- iOS Safari (12+)
|
|
415
533
|
- Android Chrome (최신)
|
|
416
534
|
|
|
535
|
+
## 더 읽어보기
|
|
536
|
+
|
|
537
|
+
- [docs/MIGRATION-v2.md](./docs/MIGRATION-v2.md) — v1 → v2 마이그레이션 가이드
|
|
538
|
+
- [docs/QUICK-START.md](./docs/QUICK-START.md) — 빠른 시작
|
|
539
|
+
- [docs/HOW-TO-USE.md](./docs/HOW-TO-USE.md) — 실제 웹사이트 적용 가이드
|
|
540
|
+
- [docs/API-KEY-GUIDE.md](./docs/API-KEY-GUIDE.md) — API 키 발급·관리 가이드
|
|
541
|
+
- [docs/AUTOCOMPLETE-GUIDE.md](./docs/AUTOCOMPLETE-GUIDE.md) — 자동완성 상세 가이드
|
|
542
|
+
- [docs/TEST-GUIDE.md](./docs/TEST-GUIDE.md) — 테스트 가이드
|
|
543
|
+
- [docs/SELF-HOSTED-DATABASE.md](./docs/SELF-HOSTED-DATABASE.md) — 자체 DB 구축
|
|
544
|
+
- [CHANGELOG.md](./CHANGELOG.md) — 버전별 변경 이력
|
|
545
|
+
|
|
417
546
|
## 라이선스
|
|
418
547
|
|
|
419
548
|
MIT License - 자유롭게 사용하세요!
|
|
420
549
|
|
|
421
550
|
## 기여하기
|
|
422
551
|
|
|
423
|
-
이슈와 PR은 언제나 환영합니다!
|
|
552
|
+
이슈와 PR은 언제나 환영합니다! 자세한 개발 절차는
|
|
553
|
+
[CONTRIBUTING.md](./CONTRIBUTING.md)를 참고하세요.
|
|
424
554
|
|
|
425
555
|
1. Fork the repository
|
|
426
556
|
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
@@ -434,7 +564,7 @@ MIT License - 자유롭게 사용하세요!
|
|
|
434
564
|
|
|
435
565
|
이 라이브러리는 **API 키가 필수**입니다. 키 없이 사용하면 동작하지 않습니다.
|
|
436
566
|
|
|
437
|
-
1. [행정안전부 도로명주소 OpenAPI](https://business.juso.go.kr/
|
|
567
|
+
1. [행정안전부 도로명주소 OpenAPI](https://business.juso.go.kr/jst/jstAddressApiApplicationWrite)에서 **"검색 API"** 키를 직접 발급받으세요. (팝업 API 아님!)
|
|
438
568
|
2. 발급받은 키를 `apiKey` 옵션으로 전달하세요:
|
|
439
569
|
```js
|
|
440
570
|
new KoreanAddressFinder({ apiKey: '발급받은_본인_키', /* ... */ });
|
|
@@ -447,7 +577,7 @@ MIT License - 자유롭게 사용하세요!
|
|
|
447
577
|
|
|
448
578
|
1. API 키가 올바른지 확인
|
|
449
579
|
2. ⚠️ **중요: API 발급 시 "검색 API"로 발급받았는지 확인** (팝업 API가 아님!)
|
|
450
|
-
3. **키 발급 시 등록한 도메인에서만 호출이 허용됩니다.** 사용할 도메인(예: `localhost`, 실제 서비스 도메인)을 juso.go.kr에 등록했는지 확인하세요.
|
|
580
|
+
3. **키 발급 시 등록한 도메인에서만 호출이 허용됩니다.** 사용할 도메인(예: `localhost`, 실제 서비스 도메인)을 juso.go.kr에 등록했는지 확인하세요. **localhost 개발에는 별도의 개발용 키가 필요합니다.**
|
|
451
581
|
4. HTTPS 사용 권장
|
|
452
582
|
|
|
453
583
|
### 검색 결과가 나오지 않아요
|
|
@@ -455,7 +585,7 @@ MIT License - 자유롭게 사용하세요!
|
|
|
455
585
|
1. 인터넷 연결 확인
|
|
456
586
|
2. API 키가 올바른지 확인
|
|
457
587
|
3. ⚠️ **API 발급 시 "검색 API"로 선택했는지 확인**
|
|
458
|
-
4. 콘솔에서 에러 메시지 확인
|
|
588
|
+
4. 콘솔에서 에러 메시지 확인 (v2부터는 `JusoApiError`가 던져지므로 원인이 명확히 보입니다)
|
|
459
589
|
|
|
460
590
|
## 지원
|
|
461
591
|
|