react-naver-maps-kit 1.0.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 (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +330 -0
  3. package/dist/core/loader/loadNaverMapsScript.d.ts +13 -0
  4. package/dist/core/loader/loadNaverMapsScript.d.ts.map +1 -0
  5. package/dist/index.cjs +2646 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.ts +36 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +2631 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/overlays/circle/Circle.d.ts +79 -0
  12. package/dist/overlays/circle/Circle.d.ts.map +1 -0
  13. package/dist/overlays/ellipse/Ellipse.d.ts +74 -0
  14. package/dist/overlays/ellipse/Ellipse.d.ts.map +1 -0
  15. package/dist/overlays/ground-overlay/GroundOverlay.d.ts +46 -0
  16. package/dist/overlays/ground-overlay/GroundOverlay.d.ts.map +1 -0
  17. package/dist/overlays/infowindow/InfoWindow.d.ts +67 -0
  18. package/dist/overlays/infowindow/InfoWindow.d.ts.map +1 -0
  19. package/dist/overlays/marker/Marker.d.ts +81 -0
  20. package/dist/overlays/marker/Marker.d.ts.map +1 -0
  21. package/dist/overlays/polygon/Polygon.d.ts +78 -0
  22. package/dist/overlays/polygon/Polygon.d.ts.map +1 -0
  23. package/dist/overlays/polyline/Polyline.d.ts +79 -0
  24. package/dist/overlays/polyline/Polyline.d.ts.map +1 -0
  25. package/dist/overlays/rectangle/Rectangle.d.ts +74 -0
  26. package/dist/overlays/rectangle/Rectangle.d.ts.map +1 -0
  27. package/dist/overlays/shared/overlayUtils.d.ts +9 -0
  28. package/dist/overlays/shared/overlayUtils.d.ts.map +1 -0
  29. package/dist/react/components/NaverMap.d.ts +137 -0
  30. package/dist/react/components/NaverMap.d.ts.map +1 -0
  31. package/dist/react/components/NaverMap.test.d.ts +2 -0
  32. package/dist/react/components/NaverMap.test.d.ts.map +1 -0
  33. package/dist/react/hooks/useNaverMap.d.ts +10 -0
  34. package/dist/react/hooks/useNaverMap.d.ts.map +1 -0
  35. package/dist/react/provider/NaverMapProvider.d.ts +21 -0
  36. package/dist/react/provider/NaverMapProvider.d.ts.map +1 -0
  37. package/package.json +84 -0
package/dist/index.js ADDED
@@ -0,0 +1,2631 @@
1
+ import { createContext, forwardRef, memo, useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
2
+ import { Fragment, jsx } from "react/jsx-runtime";
3
+ import { createPortal } from "react-dom";
4
+
5
+ //#region src/core/loader/loadNaverMapsScript.ts
6
+ const NAVER_MAPS_SCRIPT_BASE_URL = "https://oapi.map.naver.com/openapi/v3/maps.js";
7
+ let inFlightLoad = null;
8
+ let inFlightScriptUrl = null;
9
+ function getClientKey(options) {
10
+ if (options.ncpKeyId) return {
11
+ param: "ncpKeyId",
12
+ value: options.ncpKeyId
13
+ };
14
+ const legacy = [
15
+ {
16
+ param: "ncpClientId",
17
+ value: options.ncpClientId
18
+ },
19
+ {
20
+ param: "govClientId",
21
+ value: options.govClientId
22
+ },
23
+ {
24
+ param: "finClientId",
25
+ value: options.finClientId
26
+ }
27
+ ].find((candidate) => Boolean(candidate.value));
28
+ if (legacy?.value) return {
29
+ param: legacy.param,
30
+ value: legacy.value
31
+ };
32
+ throw new Error("loadNaverMapsScript requires ncpKeyId. For backward compatibility, ncpClientId, govClientId, or finClientId can be provided.");
33
+ }
34
+ function isNaverMapsReady() {
35
+ if (typeof window === "undefined") return false;
36
+ const browserWindow = window;
37
+ return Boolean(browserWindow.naver?.maps);
38
+ }
39
+ function createScriptUrl(options) {
40
+ const clientKey = getClientKey(options);
41
+ const params = new URLSearchParams();
42
+ params.set(clientKey.param, clientKey.value);
43
+ if (options.submodules && options.submodules.length > 0) params.set("submodules", options.submodules.join(","));
44
+ return `${NAVER_MAPS_SCRIPT_BASE_URL}?${params.toString()}`;
45
+ }
46
+ function waitForNaverMapsReady(timeoutMs) {
47
+ return new Promise((resolve, reject) => {
48
+ if (isNaverMapsReady()) {
49
+ resolve();
50
+ return;
51
+ }
52
+ const startedAt = Date.now();
53
+ const intervalId = setInterval(() => {
54
+ if (isNaverMapsReady()) {
55
+ clearInterval(intervalId);
56
+ resolve();
57
+ return;
58
+ }
59
+ if (Date.now() - startedAt >= timeoutMs) {
60
+ clearInterval(intervalId);
61
+ reject(/* @__PURE__ */ new Error(`Timed out after ${timeoutMs}ms while waiting for window.naver.maps.`));
62
+ }
63
+ }, 50);
64
+ });
65
+ }
66
+ function attachAuthFailureHandler(reject) {
67
+ const browserWindow = window;
68
+ const previousAuthFailure = browserWindow.navermap_authFailure;
69
+ browserWindow.navermap_authFailure = () => {
70
+ reject(/* @__PURE__ */ new Error("Naver Maps authentication failed. Check your client key and allowed domains."));
71
+ if (previousAuthFailure) previousAuthFailure();
72
+ };
73
+ return () => {
74
+ browserWindow.navermap_authFailure = previousAuthFailure;
75
+ };
76
+ }
77
+ function loadNaverMapsScript(options) {
78
+ if (typeof window === "undefined" || typeof document === "undefined") return Promise.reject(/* @__PURE__ */ new Error("loadNaverMapsScript can only run in a browser environment."));
79
+ if (isNaverMapsReady()) return Promise.resolve();
80
+ const scriptUrl = createScriptUrl(options);
81
+ if (inFlightLoad && inFlightScriptUrl === scriptUrl) return inFlightLoad;
82
+ const existingScript = document.querySelector(`script[src="${scriptUrl}"]`);
83
+ if (existingScript) {
84
+ const trackedPromise = new Promise((resolve, reject) => {
85
+ const existingScriptWithState = existingScript;
86
+ const timeoutMs = options.timeoutMs ?? 1e4;
87
+ const restoreAuthFailure = attachAuthFailureHandler(reject);
88
+ const timeoutId = setTimeout(() => {
89
+ restoreAuthFailure();
90
+ reject(/* @__PURE__ */ new Error(`Timed out after ${timeoutMs}ms while waiting for Naver Maps script.`));
91
+ }, timeoutMs);
92
+ const cleanup = () => {
93
+ clearTimeout(timeoutId);
94
+ restoreAuthFailure();
95
+ };
96
+ const handleReady = () => {
97
+ waitForNaverMapsReady(timeoutMs).then(() => {
98
+ cleanup();
99
+ resolve();
100
+ }).catch((error) => {
101
+ cleanup();
102
+ reject(error instanceof Error ? error : /* @__PURE__ */ new Error("Naver Maps is not ready."));
103
+ });
104
+ };
105
+ const onLoad = () => {
106
+ handleReady();
107
+ };
108
+ const onError = () => {
109
+ cleanup();
110
+ reject(/* @__PURE__ */ new Error("Failed to load Naver Maps script."));
111
+ };
112
+ if (existingScript.dataset.reactNaverMapsKitLoaded === "true") {
113
+ handleReady();
114
+ return;
115
+ }
116
+ if (existingScriptWithState.readyState === "loaded" || existingScriptWithState.readyState === "complete") {
117
+ handleReady();
118
+ return;
119
+ }
120
+ existingScript.addEventListener("load", onLoad, { once: true });
121
+ existingScript.addEventListener("error", onError, { once: true });
122
+ }).finally(() => {
123
+ inFlightLoad = null;
124
+ inFlightScriptUrl = null;
125
+ });
126
+ inFlightLoad = trackedPromise;
127
+ inFlightScriptUrl = scriptUrl;
128
+ return trackedPromise;
129
+ }
130
+ const trackedPromise = new Promise((resolve, reject) => {
131
+ const timeoutMs = options.timeoutMs ?? 1e4;
132
+ const script = document.createElement("script");
133
+ const restoreAuthFailure = attachAuthFailureHandler(reject);
134
+ const timeoutId = setTimeout(() => {
135
+ cleanup();
136
+ script.remove();
137
+ reject(/* @__PURE__ */ new Error(`Timed out after ${timeoutMs}ms while loading Naver Maps script.`));
138
+ }, timeoutMs);
139
+ const cleanup = () => {
140
+ script.removeEventListener("load", onLoad);
141
+ script.removeEventListener("error", onError);
142
+ clearTimeout(timeoutId);
143
+ restoreAuthFailure();
144
+ };
145
+ const onLoad = () => {
146
+ script.dataset.reactNaverMapsKitLoaded = "true";
147
+ waitForNaverMapsReady(timeoutMs).then(() => {
148
+ cleanup();
149
+ resolve();
150
+ }).catch((error) => {
151
+ cleanup();
152
+ reject(error instanceof Error ? error : /* @__PURE__ */ new Error("Naver Maps is not ready."));
153
+ });
154
+ };
155
+ const onError = () => {
156
+ cleanup();
157
+ reject(/* @__PURE__ */ new Error("Failed to load Naver Maps script."));
158
+ };
159
+ script.src = scriptUrl;
160
+ script.setAttribute("data-react-naver-maps-kit", "true");
161
+ script.type = "text/javascript";
162
+ script.async = true;
163
+ script.defer = true;
164
+ if (options.nonce) script.nonce = options.nonce;
165
+ script.addEventListener("load", onLoad);
166
+ script.addEventListener("error", onError);
167
+ document.head.append(script);
168
+ }).finally(() => {
169
+ inFlightLoad = null;
170
+ inFlightScriptUrl = null;
171
+ });
172
+ inFlightLoad = trackedPromise;
173
+ inFlightScriptUrl = scriptUrl;
174
+ return trackedPromise;
175
+ }
176
+
177
+ //#endregion
178
+ //#region src/react/provider/NaverMapProvider.tsx
179
+ const NaverMapContext = createContext(null);
180
+ function NaverMapProvider({ children, autoLoad = true, onReady, onError, ncpKeyId, ncpClientId, govClientId, finClientId, submodules, timeoutMs, nonce }) {
181
+ const [sdkStatus, setSdkStatus] = useState("idle");
182
+ const [sdkError, setSdkError] = useState(null);
183
+ const [map, setMap] = useState(null);
184
+ const mountedRef = useRef(true);
185
+ const inFlightLoadRef = useRef(null);
186
+ useEffect(() => {
187
+ mountedRef.current = true;
188
+ return () => {
189
+ mountedRef.current = false;
190
+ };
191
+ }, []);
192
+ useEffect(() => {
193
+ if (typeof window === "undefined") return;
194
+ const browserWindow = window;
195
+ const previousAuthFailure = browserWindow.navermap_authFailure;
196
+ browserWindow.navermap_authFailure = () => {
197
+ const error = /* @__PURE__ */ new Error("Naver Maps authentication failed. Check key type (ncpKeyId) and allowed domain settings.");
198
+ if (mountedRef.current) {
199
+ setSdkStatus("error");
200
+ setSdkError(error);
201
+ }
202
+ onError?.(error);
203
+ if (previousAuthFailure) previousAuthFailure();
204
+ };
205
+ return () => {
206
+ browserWindow.navermap_authFailure = previousAuthFailure;
207
+ };
208
+ }, [onError]);
209
+ const reloadSdk = useCallback(async () => {
210
+ if (inFlightLoadRef.current) return inFlightLoadRef.current;
211
+ if (mountedRef.current) {
212
+ setSdkStatus("loading");
213
+ setSdkError(null);
214
+ }
215
+ const loadPromise = loadNaverMapsScript({
216
+ ncpKeyId,
217
+ ncpClientId,
218
+ govClientId,
219
+ finClientId,
220
+ submodules,
221
+ timeoutMs,
222
+ nonce
223
+ }).then(() => {
224
+ if (mountedRef.current) {
225
+ setSdkStatus("ready");
226
+ setSdkError(null);
227
+ }
228
+ onReady?.();
229
+ }).catch((error) => {
230
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to load Naver Maps SDK.");
231
+ if (mountedRef.current) {
232
+ setSdkStatus("error");
233
+ setSdkError(normalizedError);
234
+ }
235
+ onError?.(normalizedError);
236
+ throw normalizedError;
237
+ }).finally(() => {
238
+ inFlightLoadRef.current = null;
239
+ });
240
+ inFlightLoadRef.current = loadPromise;
241
+ return loadPromise;
242
+ }, [
243
+ finClientId,
244
+ govClientId,
245
+ ncpClientId,
246
+ ncpKeyId,
247
+ nonce,
248
+ onError,
249
+ onReady,
250
+ submodules,
251
+ timeoutMs
252
+ ]);
253
+ useEffect(() => {
254
+ if (!autoLoad) return;
255
+ reloadSdk().catch(() => void 0);
256
+ }, [autoLoad, reloadSdk]);
257
+ const clearSdkError = useCallback(() => {
258
+ if (mountedRef.current) {
259
+ setSdkError(null);
260
+ setSdkStatus((current) => current === "error" ? "idle" : current);
261
+ }
262
+ }, []);
263
+ const value = useMemo(() => ({
264
+ sdkStatus,
265
+ sdkError,
266
+ map,
267
+ setMap,
268
+ reloadSdk,
269
+ retrySdk: reloadSdk,
270
+ clearSdkError
271
+ }), [
272
+ clearSdkError,
273
+ map,
274
+ reloadSdk,
275
+ sdkError,
276
+ sdkStatus
277
+ ]);
278
+ return /* @__PURE__ */ jsx(NaverMapContext.Provider, {
279
+ value,
280
+ children
281
+ });
282
+ }
283
+
284
+ //#endregion
285
+ //#region src/react/components/NaverMap.tsx
286
+ const MAP_OPTION_KEYS = [
287
+ "background",
288
+ "baseTileOpacity",
289
+ "bounds",
290
+ "center",
291
+ "zoom",
292
+ "disableDoubleClickZoom",
293
+ "disableDoubleTapZoom",
294
+ "disableKineticPan",
295
+ "disableTwoFingerTapZoom",
296
+ "draggable",
297
+ "keyboardShortcuts",
298
+ "logoControl",
299
+ "logoControlOptions",
300
+ "mapDataControl",
301
+ "mapDataControlOptions",
302
+ "mapTypeControl",
303
+ "mapTypeControlOptions",
304
+ "mapTypeId",
305
+ "mapTypes",
306
+ "maxBounds",
307
+ "maxZoom",
308
+ "minZoom",
309
+ "padding",
310
+ "pinchZoom",
311
+ "resizeOrigin",
312
+ "scaleControl",
313
+ "scaleControlOptions",
314
+ "scrollWheel",
315
+ "size",
316
+ "overlayZoomEffect",
317
+ "tileSpare",
318
+ "tileTransition",
319
+ "tileDuration",
320
+ "zoomControl",
321
+ "zoomControlOptions",
322
+ "zoomOrigin",
323
+ "blankTileImage",
324
+ "gl",
325
+ "customStyleId"
326
+ ];
327
+ const MAP_OPTION_KEY_SET = new Set(MAP_OPTION_KEYS);
328
+ const MAP_EVENT_PROP_KEY_SET = new Set([
329
+ "onAddLayer",
330
+ "onBoundsChanged",
331
+ "onCenterChanged",
332
+ "onCenterPointChanged",
333
+ "onClick",
334
+ "onDblClick",
335
+ "onDoubleTap",
336
+ "onDrag",
337
+ "onDragEnd",
338
+ "onDragStart",
339
+ "onIdle",
340
+ "onInit",
341
+ "onKeyDown",
342
+ "onKeyUp",
343
+ "onLongTap",
344
+ "onMapTypeChanged",
345
+ "onMapTypeIdChanged",
346
+ "onMouseDown",
347
+ "onMouseMove",
348
+ "onMouseOut",
349
+ "onMouseOver",
350
+ "onMouseUp",
351
+ "onPanning",
352
+ "onPinch",
353
+ "onPinchEnd",
354
+ "onPinchStart",
355
+ "onProjectionChanged",
356
+ "onRemoveLayer",
357
+ "onResize",
358
+ "onRightClick",
359
+ "onSingleTap",
360
+ "onTouchEnd",
361
+ "onTouchMove",
362
+ "onTouchStart",
363
+ "onTwoFingerTap",
364
+ "onWheel",
365
+ "onZoomChanged",
366
+ "onZooming",
367
+ "onZoomStart"
368
+ ]);
369
+ const MAP_EVENT_BINDINGS = [
370
+ {
371
+ prop: "onAddLayer",
372
+ eventName: "addLayer",
373
+ hasPayload: true
374
+ },
375
+ {
376
+ prop: "onBoundsChanged",
377
+ eventName: "bounds_changed",
378
+ hasPayload: true
379
+ },
380
+ {
381
+ prop: "onCenterChanged",
382
+ eventName: "center_changed",
383
+ hasPayload: true
384
+ },
385
+ {
386
+ prop: "onCenterPointChanged",
387
+ eventName: "centerPoint_changed",
388
+ hasPayload: true
389
+ },
390
+ {
391
+ prop: "onClick",
392
+ eventName: "click",
393
+ hasPayload: true
394
+ },
395
+ {
396
+ prop: "onDblClick",
397
+ eventName: "dblclick",
398
+ hasPayload: true
399
+ },
400
+ {
401
+ prop: "onDoubleTap",
402
+ eventName: "doubletap",
403
+ hasPayload: true
404
+ },
405
+ {
406
+ prop: "onDrag",
407
+ eventName: "drag",
408
+ hasPayload: true
409
+ },
410
+ {
411
+ prop: "onDragEnd",
412
+ eventName: "dragend",
413
+ hasPayload: true
414
+ },
415
+ {
416
+ prop: "onDragStart",
417
+ eventName: "dragstart",
418
+ hasPayload: true
419
+ },
420
+ {
421
+ prop: "onIdle",
422
+ eventName: "idle",
423
+ hasPayload: false
424
+ },
425
+ {
426
+ prop: "onInit",
427
+ eventName: "init",
428
+ hasPayload: false
429
+ },
430
+ {
431
+ prop: "onKeyDown",
432
+ eventName: "keydown",
433
+ hasPayload: true
434
+ },
435
+ {
436
+ prop: "onKeyUp",
437
+ eventName: "keyup",
438
+ hasPayload: true
439
+ },
440
+ {
441
+ prop: "onLongTap",
442
+ eventName: "longtap",
443
+ hasPayload: true
444
+ },
445
+ {
446
+ prop: "onMapTypeChanged",
447
+ eventName: "mapType_changed",
448
+ hasPayload: true
449
+ },
450
+ {
451
+ prop: "onMapTypeIdChanged",
452
+ eventName: "mapTypeId_changed",
453
+ hasPayload: true
454
+ },
455
+ {
456
+ prop: "onMouseDown",
457
+ eventName: "mousedown",
458
+ hasPayload: true
459
+ },
460
+ {
461
+ prop: "onMouseMove",
462
+ eventName: "mousemove",
463
+ hasPayload: true
464
+ },
465
+ {
466
+ prop: "onMouseOut",
467
+ eventName: "mouseout",
468
+ hasPayload: true
469
+ },
470
+ {
471
+ prop: "onMouseOver",
472
+ eventName: "mouseover",
473
+ hasPayload: true
474
+ },
475
+ {
476
+ prop: "onMouseUp",
477
+ eventName: "mouseup",
478
+ hasPayload: true
479
+ },
480
+ {
481
+ prop: "onPanning",
482
+ eventName: "panning",
483
+ hasPayload: false
484
+ },
485
+ {
486
+ prop: "onPinch",
487
+ eventName: "pinch",
488
+ hasPayload: true
489
+ },
490
+ {
491
+ prop: "onPinchEnd",
492
+ eventName: "pinchend",
493
+ hasPayload: true
494
+ },
495
+ {
496
+ prop: "onPinchStart",
497
+ eventName: "pinchstart",
498
+ hasPayload: true
499
+ },
500
+ {
501
+ prop: "onProjectionChanged",
502
+ eventName: "projection_changed",
503
+ hasPayload: true
504
+ },
505
+ {
506
+ prop: "onRemoveLayer",
507
+ eventName: "removeLayer",
508
+ hasPayload: true
509
+ },
510
+ {
511
+ prop: "onResize",
512
+ eventName: "resize",
513
+ hasPayload: false
514
+ },
515
+ {
516
+ prop: "onRightClick",
517
+ eventName: "rightclick",
518
+ hasPayload: true
519
+ },
520
+ {
521
+ prop: "onSingleTap",
522
+ eventName: "singletap",
523
+ hasPayload: true
524
+ },
525
+ {
526
+ prop: "onTouchEnd",
527
+ eventName: "touchend",
528
+ hasPayload: true
529
+ },
530
+ {
531
+ prop: "onTouchMove",
532
+ eventName: "touchmove",
533
+ hasPayload: true
534
+ },
535
+ {
536
+ prop: "onTouchStart",
537
+ eventName: "touchstart",
538
+ hasPayload: true
539
+ },
540
+ {
541
+ prop: "onTwoFingerTap",
542
+ eventName: "twofingertap",
543
+ hasPayload: true
544
+ },
545
+ {
546
+ prop: "onWheel",
547
+ eventName: "wheel",
548
+ hasPayload: true
549
+ },
550
+ {
551
+ prop: "onZoomChanged",
552
+ eventName: "zoom_changed",
553
+ hasPayload: true
554
+ },
555
+ {
556
+ prop: "onZooming",
557
+ eventName: "zooming",
558
+ hasPayload: false
559
+ },
560
+ {
561
+ prop: "onZoomStart",
562
+ eventName: "zoomstart",
563
+ hasPayload: false
564
+ }
565
+ ];
566
+ const NON_DIV_KEYS = new Set([
567
+ "onMapReady",
568
+ "onMapDestroy",
569
+ "onMapError",
570
+ "retryOnError",
571
+ "retryDelayMs",
572
+ "fallback",
573
+ "defaultCenter",
574
+ "defaultZoom",
575
+ "children"
576
+ ]);
577
+ function toCenterSignature(center) {
578
+ if (!center) return "";
579
+ if (typeof center === "object") {
580
+ const candidate = center;
581
+ const rawLat = candidate.lat;
582
+ const rawLng = candidate.lng;
583
+ const lat = typeof rawLat === "function" ? rawLat() : rawLat;
584
+ const lng = typeof rawLng === "function" ? rawLng() : rawLng;
585
+ if (typeof lat === "number" && typeof lng === "number") return `latlng:${lat},${lng}`;
586
+ const rawX = candidate.x;
587
+ const rawY = candidate.y;
588
+ const x = typeof rawX === "function" ? rawX() : rawX;
589
+ const y = typeof rawY === "function" ? rawY() : rawY;
590
+ if (typeof x === "number" && typeof y === "number") return `xy:${x},${y}`;
591
+ }
592
+ return String(center);
593
+ }
594
+ function areValuesEqual(left, right) {
595
+ if (left === right) return true;
596
+ if (left === null || right === null || left === void 0 || right === void 0) return false;
597
+ if (typeof left === "object" && typeof right === "object") {
598
+ const leftCenter = toCenterSignature(left);
599
+ const rightCenter = toCenterSignature(right);
600
+ if (leftCenter !== "" && rightCenter !== "") return leftCenter === rightCenter;
601
+ return JSON.stringify(left) === JSON.stringify(right);
602
+ }
603
+ return false;
604
+ }
605
+ function getChangedOptions(previous, next) {
606
+ const keys = new Set([...Object.keys(previous), ...Object.keys(next)]);
607
+ const changed = [];
608
+ for (const key of keys) {
609
+ const typedKey = key;
610
+ const previousValue = previous[typedKey];
611
+ const nextValue = next[typedKey];
612
+ if (!areValuesEqual(previousValue, nextValue) && nextValue !== void 0) changed.push([key, nextValue]);
613
+ }
614
+ return Object.fromEntries(changed);
615
+ }
616
+ function getDivProps(props) {
617
+ const entries = [];
618
+ for (const [key, value] of Object.entries(props)) {
619
+ if (NON_DIV_KEYS.has(key) || MAP_OPTION_KEY_SET.has(key) || MAP_EVENT_PROP_KEY_SET.has(key)) continue;
620
+ entries.push([key, value]);
621
+ }
622
+ return Object.fromEntries(entries);
623
+ }
624
+ /**
625
+ * memo 비교: children과 함수(콜백)는 skip.
626
+ * - children: React element는 JSON.stringify 불가
627
+ * - 함수: ref를 통해 항상 최신 값을 읽으므로 비교 불필요
628
+ */
629
+ function areNaverMapPropsEqual(previousProps, nextProps) {
630
+ const keys = new Set([...Object.keys(previousProps), ...Object.keys(nextProps)]);
631
+ for (const key of keys) {
632
+ if (key === "children") continue;
633
+ const previousValue = previousProps[key];
634
+ const nextValue = nextProps[key];
635
+ if (typeof previousValue === "function" && typeof nextValue === "function") continue;
636
+ if (!areValuesEqual(previousValue, nextValue)) return false;
637
+ }
638
+ return true;
639
+ }
640
+ const NaverMapBase = forwardRef(function NaverMapInner(props, ref) {
641
+ const context = useContext(NaverMapContext);
642
+ if (!context) throw new Error("NaverMap must be used inside NaverMapProvider.");
643
+ const { sdkStatus, setMap, reloadSdk } = context;
644
+ const [mapReady, setMapReady] = useState(false);
645
+ const propsRef = useRef(props);
646
+ useEffect(() => {
647
+ propsRef.current = props;
648
+ });
649
+ const initialCenterRef = useRef(props.center ?? props.defaultCenter);
650
+ const initialZoomRef = useRef(props.zoom ?? props.defaultZoom);
651
+ const isControlledCenter = props.center !== void 0;
652
+ const isControlledZoom = props.zoom !== void 0;
653
+ const mapOptions = useMemo(() => {
654
+ const entries = [];
655
+ for (const key of MAP_OPTION_KEYS) {
656
+ const value = props[key];
657
+ if (value !== void 0) entries.push([key, value]);
658
+ }
659
+ return Object.fromEntries(entries);
660
+ }, [
661
+ props.background,
662
+ props.baseTileOpacity,
663
+ props.bounds,
664
+ props.center,
665
+ props.zoom,
666
+ props.disableDoubleClickZoom,
667
+ props.disableDoubleTapZoom,
668
+ props.disableKineticPan,
669
+ props.disableTwoFingerTapZoom,
670
+ props.draggable,
671
+ props.keyboardShortcuts,
672
+ props.logoControl,
673
+ props.logoControlOptions,
674
+ props.mapDataControl,
675
+ props.mapDataControlOptions,
676
+ props.mapTypeControl,
677
+ props.mapTypeControlOptions,
678
+ props.mapTypeId,
679
+ props.mapTypes,
680
+ props.maxBounds,
681
+ props.maxZoom,
682
+ props.minZoom,
683
+ props.padding,
684
+ props.pinchZoom,
685
+ props.resizeOrigin,
686
+ props.scaleControl,
687
+ props.scaleControlOptions,
688
+ props.scrollWheel,
689
+ props.size,
690
+ props.overlayZoomEffect,
691
+ props.tileSpare,
692
+ props.tileTransition,
693
+ props.tileDuration,
694
+ props.zoomControl,
695
+ props.zoomControlOptions,
696
+ props.zoomOrigin,
697
+ props.blankTileImage,
698
+ props.gl,
699
+ props.customStyleId
700
+ ]);
701
+ const divProps = useMemo(() => getDivProps(props), [props]);
702
+ const containerRef = useRef(null);
703
+ const mapRef = useRef(null);
704
+ const appliedOptionsRef = useRef({});
705
+ const retryTimerRef = useRef(null);
706
+ const mapOptionsRef = useRef(mapOptions);
707
+ mapOptionsRef.current = mapOptions;
708
+ const invokeMapMethod = useCallback((methodName, ...args) => {
709
+ const mapInstance = mapRef.current;
710
+ if (!mapInstance) return;
711
+ const method = mapInstance[methodName];
712
+ if (typeof method !== "function") return;
713
+ return method.apply(mapInstance, args);
714
+ }, []);
715
+ useImperativeHandle(ref, () => ({
716
+ getInstance: () => mapRef.current,
717
+ addOverlayPane: (name, elementOrZIndex) => {
718
+ mapRef.current?.addOverlayPane?.(name, elementOrZIndex);
719
+ },
720
+ addPane: (...args) => invokeMapMethod("addPane", ...args),
721
+ autoResize: (...args) => invokeMapMethod("autoResize", ...args),
722
+ destroy: (...args) => {
723
+ const mapInstance = mapRef.current;
724
+ if (!mapInstance) return;
725
+ try {
726
+ return mapInstance.destroy?.(...args);
727
+ } catch {
728
+ return;
729
+ }
730
+ },
731
+ fitBounds: (...args) => invokeMapMethod("fitBounds", ...args),
732
+ getBounds: (...args) => invokeMapMethod("getBounds", ...args),
733
+ getCenter: (...args) => invokeMapMethod("getCenter", ...args),
734
+ getCenterPoint: (...args) => invokeMapMethod("getCenterPoint", ...args),
735
+ getElement: (...args) => invokeMapMethod("getElement", ...args),
736
+ getMapTypeId: (...args) => invokeMapMethod("getMapTypeId", ...args),
737
+ getMaxZoom: (...args) => invokeMapMethod("getMaxZoom", ...args),
738
+ getMinZoom: (...args) => invokeMapMethod("getMinZoom", ...args),
739
+ getOptions: (...args) => invokeMapMethod("getOptions", ...args),
740
+ getPanes: (...args) => invokeMapMethod("getPanes", ...args),
741
+ getPrimitiveProjection: (...args) => invokeMapMethod("getPrimitiveProjection", ...args),
742
+ getProjection: (...args) => invokeMapMethod("getProjection", ...args),
743
+ getSize: (...args) => invokeMapMethod("getSize", ...args),
744
+ getZoom: (...args) => invokeMapMethod("getZoom", ...args),
745
+ morph: (...args) => invokeMapMethod("morph", ...args),
746
+ panBy: (...args) => invokeMapMethod("panBy", ...args),
747
+ panTo: (...args) => invokeMapMethod("panTo", ...args),
748
+ panToBounds: (...args) => invokeMapMethod("panToBounds", ...args),
749
+ refresh: (...args) => invokeMapMethod("refresh", ...args),
750
+ removeOverlayPane: (name) => {
751
+ mapRef.current?.removeOverlayPane?.(name);
752
+ },
753
+ removePane: (...args) => invokeMapMethod("removePane", ...args),
754
+ setCenter: (...args) => invokeMapMethod("setCenter", ...args),
755
+ setCenterPoint: (...args) => invokeMapMethod("setCenterPoint", ...args),
756
+ setMapTypeId: (...args) => invokeMapMethod("setMapTypeId", ...args),
757
+ setOptions: (...args) => invokeMapMethod("setOptions", ...args),
758
+ setSize: (...args) => invokeMapMethod("setSize", ...args),
759
+ setZoom: (...args) => invokeMapMethod("setZoom", ...args),
760
+ stop: (...args) => invokeMapMethod("stop", ...args),
761
+ updateBy: (...args) => invokeMapMethod("updateBy", ...args),
762
+ zoomBy: (...args) => invokeMapMethod("zoomBy", ...args)
763
+ }), [invokeMapMethod]);
764
+ useEffect(() => {
765
+ if (sdkStatus !== "ready" || !containerRef.current) return;
766
+ const container = containerRef.current;
767
+ const initOptions = { ...mapOptionsRef.current };
768
+ if (initOptions.center === void 0 && initialCenterRef.current !== void 0) initOptions.center = initialCenterRef.current;
769
+ if (initOptions.zoom === void 0 && initialZoomRef.current !== void 0) initOptions.zoom = initialZoomRef.current;
770
+ let mapInstance;
771
+ try {
772
+ mapInstance = new naver.maps.Map(container, initOptions);
773
+ } catch (error) {
774
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Map instance.");
775
+ propsRef.current.onMapError?.(normalizedError);
776
+ if (propsRef.current.retryOnError) retryTimerRef.current = setTimeout(() => {
777
+ reloadSdk().catch(() => void 0);
778
+ }, propsRef.current.retryDelayMs ?? 1e3);
779
+ return () => {
780
+ if (retryTimerRef.current) {
781
+ clearTimeout(retryTimerRef.current);
782
+ retryTimerRef.current = null;
783
+ }
784
+ };
785
+ }
786
+ mapRef.current = mapInstance;
787
+ appliedOptionsRef.current = initOptions;
788
+ setMap(mapInstance);
789
+ setMapReady(true);
790
+ propsRef.current.onMapReady?.(mapInstance);
791
+ const listeners = MAP_EVENT_BINDINGS.map((binding) => naver.maps.Event.addListener(mapInstance, binding.eventName, (event) => {
792
+ const handler = propsRef.current[binding.prop];
793
+ if (typeof handler !== "function") return;
794
+ if (binding.hasPayload) handler(event);
795
+ else handler();
796
+ }));
797
+ return () => {
798
+ try {
799
+ naver.maps.Event.removeListener(listeners);
800
+ naver.maps.Event.clearInstanceListeners(mapInstance);
801
+ } catch {}
802
+ if (retryTimerRef.current) {
803
+ clearTimeout(retryTimerRef.current);
804
+ retryTimerRef.current = null;
805
+ }
806
+ container.innerHTML = "";
807
+ mapRef.current = null;
808
+ appliedOptionsRef.current = {};
809
+ setMap(null);
810
+ setMapReady(false);
811
+ propsRef.current.onMapDestroy?.();
812
+ };
813
+ }, [
814
+ sdkStatus,
815
+ setMap,
816
+ reloadSdk
817
+ ]);
818
+ useEffect(() => {
819
+ const mapInstance = mapRef.current;
820
+ if (!mapInstance) return;
821
+ const changed = getChangedOptions(appliedOptionsRef.current, mapOptions);
822
+ if (Object.keys(changed).length === 0) {
823
+ appliedOptionsRef.current = mapOptions;
824
+ return;
825
+ }
826
+ const { center: changedCenter, zoom: changedZoom, mapTypeId: changedMapTypeId, ...otherChanged } = changed;
827
+ const savedCenter = !isControlledCenter ? mapInstance.getCenter() : null;
828
+ const savedZoom = !isControlledZoom ? mapInstance.getZoom() : null;
829
+ if (Object.keys(otherChanged).length > 0) mapInstance.setOptions(otherChanged);
830
+ if (changedMapTypeId !== void 0 && mapOptions.mapTypeId !== void 0) mapInstance.setMapTypeId(mapOptions.mapTypeId);
831
+ if (isControlledCenter && changedCenter !== void 0) mapInstance.setCenter(changedCenter);
832
+ if (isControlledZoom && changedZoom !== void 0 && mapOptions.zoom !== void 0) mapInstance.setZoom(mapOptions.zoom);
833
+ if (savedCenter) mapInstance.setCenter(savedCenter);
834
+ if (savedZoom !== null) mapInstance.setZoom(savedZoom);
835
+ appliedOptionsRef.current = mapOptions;
836
+ }, [
837
+ mapOptions,
838
+ isControlledCenter,
839
+ isControlledZoom
840
+ ]);
841
+ if (sdkStatus === "error") return /* @__PURE__ */ jsx(Fragment, { children: props.fallback ?? /* @__PURE__ */ jsx("div", {
842
+ ...divProps,
843
+ children: "지도를 불러올 수 없습니다."
844
+ }) });
845
+ if (sdkStatus === "loading") return /* @__PURE__ */ jsx(Fragment, { children: props.fallback ?? /* @__PURE__ */ jsx("div", { ...divProps }) });
846
+ return /* @__PURE__ */ jsx("div", {
847
+ ref: containerRef,
848
+ ...divProps,
849
+ children: mapReady ? props.children : null
850
+ });
851
+ });
852
+ NaverMapBase.displayName = "NaverMap";
853
+ const NaverMap = memo(NaverMapBase, areNaverMapPropsEqual);
854
+
855
+ //#endregion
856
+ //#region src/react/hooks/useNaverMap.ts
857
+ function useNaverMap(options = {}) {
858
+ const context = useContext(NaverMapContext);
859
+ if (!context) throw new Error("useNaverMap must be used within NaverMapProvider.");
860
+ if (options.requireReady && context.sdkStatus !== "ready") throw new Error(`Naver Maps SDK is not ready. Current status: ${context.sdkStatus}.`);
861
+ if (options.requireMapInstance && !context.map) throw new Error("Naver map instance is not available yet.");
862
+ return context;
863
+ }
864
+ function useNaverMapInstance(options = {}) {
865
+ return useNaverMap({
866
+ requireReady: options.requireReady,
867
+ requireMapInstance: false
868
+ }).map;
869
+ }
870
+
871
+ //#endregion
872
+ //#region src/overlays/marker/Marker.tsx
873
+ function pickHtmlIconAnchor(icon) {
874
+ if ("anchor" in icon) return icon.anchor;
875
+ }
876
+ function pickHtmlIconSize(icon) {
877
+ if ("size" in icon) return icon.size;
878
+ }
879
+ function resolveMarkerIcon(icon, childrenContainer, hasChildren) {
880
+ if (!hasChildren || !childrenContainer) return icon;
881
+ const iconObject = typeof icon === "object" && icon !== null ? icon : void 0;
882
+ return {
883
+ content: childrenContainer,
884
+ anchor: iconObject ? pickHtmlIconAnchor(iconObject) : void 0,
885
+ size: iconObject ? pickHtmlIconSize(iconObject) : void 0
886
+ };
887
+ }
888
+ function toMarkerOptions(props, targetMap, icon) {
889
+ const options = {
890
+ position: props.position,
891
+ icon
892
+ };
893
+ if (targetMap) options.map = targetMap;
894
+ if (props.animation !== void 0) options.animation = props.animation;
895
+ if (props.shape !== void 0) options.shape = props.shape;
896
+ if (props.title !== void 0) options.title = props.title;
897
+ if (props.cursor !== void 0) options.cursor = props.cursor;
898
+ if (props.clickable !== void 0) options.clickable = props.clickable;
899
+ if (props.draggable !== void 0) options.draggable = props.draggable;
900
+ if (props.visible !== void 0) options.visible = props.visible;
901
+ if (props.zIndex !== void 0) options.zIndex = props.zIndex;
902
+ return options;
903
+ }
904
+ function buildMarkerEventBindings(props) {
905
+ return [
906
+ {
907
+ eventName: "click",
908
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
909
+ },
910
+ {
911
+ eventName: "dblclick",
912
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
913
+ },
914
+ {
915
+ eventName: "rightclick",
916
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
917
+ },
918
+ {
919
+ eventName: "mousedown",
920
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
921
+ },
922
+ {
923
+ eventName: "mouseup",
924
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
925
+ },
926
+ {
927
+ eventName: "touchstart",
928
+ invoke: props.onTouchStart ? (event) => props.onTouchStart?.(event) : void 0
929
+ },
930
+ {
931
+ eventName: "touchend",
932
+ invoke: props.onTouchEnd ? (event) => props.onTouchEnd?.(event) : void 0
933
+ },
934
+ {
935
+ eventName: "dragstart",
936
+ invoke: props.onDragStart ? (event) => props.onDragStart?.(event) : void 0
937
+ },
938
+ {
939
+ eventName: "drag",
940
+ invoke: props.onDrag ? (event) => props.onDrag?.(event) : void 0
941
+ },
942
+ {
943
+ eventName: "dragend",
944
+ invoke: props.onDragEnd ? (event) => props.onDragEnd?.(event) : void 0
945
+ },
946
+ {
947
+ eventName: "clickable_changed",
948
+ invoke: props.onClickableChanged ? (event) => props.onClickableChanged?.(event) : void 0
949
+ },
950
+ {
951
+ eventName: "cursor_changed",
952
+ invoke: props.onCursorChanged ? (event) => props.onCursorChanged?.(event) : void 0
953
+ },
954
+ {
955
+ eventName: "draggable_changed",
956
+ invoke: props.onDraggableChanged ? (event) => props.onDraggableChanged?.(event) : void 0
957
+ },
958
+ {
959
+ eventName: "icon_changed",
960
+ invoke: props.onIconChanged ? (event) => props.onIconChanged?.(event) : void 0
961
+ },
962
+ {
963
+ eventName: "icon_loaded",
964
+ invoke: props.onIconLoaded ? (event) => props.onIconLoaded?.(event) : void 0
965
+ },
966
+ {
967
+ eventName: "position_changed",
968
+ invoke: props.onPositionChanged ? (event) => props.onPositionChanged?.(event) : void 0
969
+ },
970
+ {
971
+ eventName: "shape_changed",
972
+ invoke: props.onShapeChanged ? (event) => props.onShapeChanged?.(event) : void 0
973
+ },
974
+ {
975
+ eventName: "title_changed",
976
+ invoke: props.onTitleChanged ? (event) => props.onTitleChanged?.(event) : void 0
977
+ },
978
+ {
979
+ eventName: "visible_changed",
980
+ invoke: props.onVisibleChanged ? (event) => props.onVisibleChanged?.(event) : void 0
981
+ },
982
+ {
983
+ eventName: "zIndex_changed",
984
+ invoke: props.onZIndexChanged ? (event) => props.onZIndexChanged?.(event) : void 0
985
+ }
986
+ ];
987
+ }
988
+ function bindMarkerEventListeners(marker, listenersRef, bindings) {
989
+ if (listenersRef.current.length > 0) {
990
+ naver.maps.Event.removeListener(listenersRef.current);
991
+ listenersRef.current = [];
992
+ }
993
+ listenersRef.current = bindings.filter((binding) => typeof binding.invoke === "function").map((binding) => naver.maps.Event.addListener(marker, binding.eventName, (event) => {
994
+ binding.invoke?.(event);
995
+ }));
996
+ }
997
+ const Marker = forwardRef(function MarkerInner(props, ref) {
998
+ const { map: contextMap, sdkStatus } = useNaverMap();
999
+ const markerRef = useRef(null);
1000
+ const markerEventListenersRef = useRef([]);
1001
+ const onMarkerDestroyRef = useRef(props.onMarkerDestroy);
1002
+ const [markerDiv, setMarkerDiv] = useState(null);
1003
+ const [portalReady, setPortalReady] = useState(false);
1004
+ const hasChildren = props.children !== void 0 && props.children !== null;
1005
+ const targetMap = props.map ?? contextMap;
1006
+ useEffect(() => {
1007
+ onMarkerDestroyRef.current = props.onMarkerDestroy;
1008
+ }, [props.onMarkerDestroy]);
1009
+ useEffect(() => {
1010
+ if (typeof document === "undefined") return;
1011
+ setMarkerDiv(document.createElement("div"));
1012
+ }, []);
1013
+ useEffect(() => {
1014
+ if (!hasChildren || !markerDiv) {
1015
+ setPortalReady(false);
1016
+ return;
1017
+ }
1018
+ const updateReadyState = () => {
1019
+ setPortalReady(markerDiv.childNodes.length > 0);
1020
+ };
1021
+ updateReadyState();
1022
+ const observer = new MutationObserver(updateReadyState);
1023
+ observer.observe(markerDiv, {
1024
+ childList: true,
1025
+ subtree: true
1026
+ });
1027
+ return () => {
1028
+ observer.disconnect();
1029
+ };
1030
+ }, [hasChildren, markerDiv]);
1031
+ const invokeMarkerMethod = useCallback((methodName, ...args) => {
1032
+ const marker = markerRef.current;
1033
+ if (!marker) return;
1034
+ const method = marker[methodName];
1035
+ if (typeof method !== "function") return;
1036
+ return method.apply(marker, args);
1037
+ }, []);
1038
+ const teardownMarker = useCallback(() => {
1039
+ const marker = markerRef.current;
1040
+ if (!marker) return;
1041
+ try {
1042
+ if (markerEventListenersRef.current.length > 0) {
1043
+ naver.maps.Event.removeListener(markerEventListenersRef.current);
1044
+ markerEventListenersRef.current = [];
1045
+ }
1046
+ naver.maps.Event.clearInstanceListeners(marker);
1047
+ } catch (error) {
1048
+ console.error("[react-naver-maps-kit] failed to clear marker listeners", error);
1049
+ }
1050
+ marker.setMap(null);
1051
+ markerRef.current = null;
1052
+ onMarkerDestroyRef.current?.();
1053
+ }, []);
1054
+ useImperativeHandle(ref, () => ({
1055
+ getInstance: () => markerRef.current,
1056
+ getAnimation: (...args) => invokeMarkerMethod("getAnimation", ...args),
1057
+ getClickable: (...args) => invokeMarkerMethod("getClickable", ...args),
1058
+ getCursor: (...args) => invokeMarkerMethod("getCursor", ...args),
1059
+ getDraggable: (...args) => invokeMarkerMethod("getDraggable", ...args),
1060
+ getDrawingRect: (...args) => invokeMarkerMethod("getDrawingRect", ...args),
1061
+ getElement: (...args) => invokeMarkerMethod("getElement", ...args),
1062
+ getIcon: (...args) => invokeMarkerMethod("getIcon", ...args),
1063
+ getMap: (...args) => invokeMarkerMethod("getMap", ...args),
1064
+ getOptions: (...args) => invokeMarkerMethod("getOptions", ...args),
1065
+ getPanes: (...args) => invokeMarkerMethod("getPanes", ...args),
1066
+ getPosition: (...args) => invokeMarkerMethod("getPosition", ...args),
1067
+ getProjection: (...args) => invokeMarkerMethod("getProjection", ...args),
1068
+ getShape: (...args) => invokeMarkerMethod("getShape", ...args),
1069
+ getTitle: (...args) => invokeMarkerMethod("getTitle", ...args),
1070
+ getVisible: (...args) => invokeMarkerMethod("getVisible", ...args),
1071
+ getZIndex: (...args) => invokeMarkerMethod("getZIndex", ...args),
1072
+ setAnimation: (...args) => invokeMarkerMethod("setAnimation", ...args),
1073
+ setClickable: (...args) => invokeMarkerMethod("setClickable", ...args),
1074
+ setCursor: (...args) => invokeMarkerMethod("setCursor", ...args),
1075
+ setDraggable: (...args) => invokeMarkerMethod("setDraggable", ...args),
1076
+ setIcon: (...args) => invokeMarkerMethod("setIcon", ...args),
1077
+ setMap: (...args) => invokeMarkerMethod("setMap", ...args),
1078
+ setOptions: (...args) => invokeMarkerMethod("setOptions", ...args),
1079
+ setPosition: (...args) => invokeMarkerMethod("setPosition", ...args),
1080
+ setShape: (...args) => invokeMarkerMethod("setShape", ...args),
1081
+ setTitle: (...args) => invokeMarkerMethod("setTitle", ...args),
1082
+ setVisible: (...args) => invokeMarkerMethod("setVisible", ...args),
1083
+ setZIndex: (...args) => invokeMarkerMethod("setZIndex", ...args)
1084
+ }), [invokeMarkerMethod]);
1085
+ useEffect(() => {
1086
+ if (sdkStatus !== "ready" || !targetMap || markerRef.current) return;
1087
+ if (hasChildren && !portalReady) return;
1088
+ try {
1089
+ const resolvedIcon = resolveMarkerIcon(props.icon, markerDiv, hasChildren);
1090
+ const marker = new naver.maps.Marker(toMarkerOptions(props, targetMap, resolvedIcon));
1091
+ markerRef.current = marker;
1092
+ if (props.collisionBehavior !== void 0) marker.setOptions("collisionBehavior", props.collisionBehavior);
1093
+ if (props.collisionBoxSize !== void 0) marker.setOptions("collisionBoxSize", props.collisionBoxSize);
1094
+ bindMarkerEventListeners(marker, markerEventListenersRef, buildMarkerEventBindings(props));
1095
+ props.onMarkerReady?.(marker);
1096
+ } catch (error) {
1097
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Marker instance.");
1098
+ props.onMarkerError?.(normalizedError);
1099
+ }
1100
+ }, [
1101
+ hasChildren,
1102
+ markerDiv,
1103
+ portalReady,
1104
+ props,
1105
+ sdkStatus,
1106
+ targetMap
1107
+ ]);
1108
+ useLayoutEffect(() => {
1109
+ const marker = markerRef.current;
1110
+ if (!marker || !targetMap) return;
1111
+ const rafId = requestAnimationFrame(() => {
1112
+ const nextOptions = toMarkerOptions(props, targetMap, hasChildren && portalReady ? resolveMarkerIcon(props.icon, markerDiv, hasChildren) : props.icon);
1113
+ marker.setOptions(nextOptions);
1114
+ if (props.collisionBehavior !== void 0) marker.setOptions("collisionBehavior", props.collisionBehavior);
1115
+ if (props.collisionBoxSize !== void 0) marker.setOptions("collisionBoxSize", props.collisionBoxSize);
1116
+ });
1117
+ return () => {
1118
+ cancelAnimationFrame(rafId);
1119
+ };
1120
+ }, [
1121
+ hasChildren,
1122
+ markerDiv,
1123
+ portalReady,
1124
+ props,
1125
+ targetMap
1126
+ ]);
1127
+ useEffect(() => {
1128
+ const marker = markerRef.current;
1129
+ if (!marker) return;
1130
+ bindMarkerEventListeners(marker, markerEventListenersRef, buildMarkerEventBindings(props));
1131
+ return () => {
1132
+ if (markerEventListenersRef.current.length > 0) {
1133
+ naver.maps.Event.removeListener(markerEventListenersRef.current);
1134
+ markerEventListenersRef.current = [];
1135
+ }
1136
+ };
1137
+ }, [props]);
1138
+ useEffect(() => {
1139
+ return () => {
1140
+ teardownMarker();
1141
+ };
1142
+ }, [teardownMarker]);
1143
+ if (!hasChildren || !markerDiv) return null;
1144
+ return createPortal(props.children, markerDiv);
1145
+ });
1146
+ Marker.displayName = "Marker";
1147
+
1148
+ //#endregion
1149
+ //#region src/overlays/infowindow/InfoWindow.tsx
1150
+ function toInfoWindowOptions(props) {
1151
+ const { anchorColor, anchorSize, anchorSkew, backgroundColor, borderColor, borderWidth, disableAnchor, disableAutoPan, maxWidth, pixelOffset, position, zIndex } = props;
1152
+ const options = {};
1153
+ if (anchorColor !== void 0) options.anchorColor = anchorColor;
1154
+ if (anchorSize !== void 0) options.anchorSize = anchorSize;
1155
+ if (anchorSkew !== void 0) options.anchorSkew = anchorSkew;
1156
+ if (backgroundColor !== void 0) options.backgroundColor = backgroundColor;
1157
+ if (borderColor !== void 0) options.borderColor = borderColor;
1158
+ if (borderWidth !== void 0) options.borderWidth = borderWidth;
1159
+ if (disableAnchor !== void 0) options.disableAnchor = disableAnchor;
1160
+ if (disableAutoPan !== void 0) options.disableAutoPan = disableAutoPan;
1161
+ if (maxWidth !== void 0) options.maxWidth = maxWidth;
1162
+ if (pixelOffset !== void 0) options.pixelOffset = pixelOffset;
1163
+ if (position !== void 0) options.position = position;
1164
+ if (zIndex !== void 0) options.zIndex = zIndex;
1165
+ return options;
1166
+ }
1167
+ function resolveInfoWindowContent(content, childrenContainer, hasChildren) {
1168
+ if (hasChildren && childrenContainer) return childrenContainer;
1169
+ if (content !== void 0) return content;
1170
+ return "";
1171
+ }
1172
+ function buildInfoWindowEventBindings(props) {
1173
+ return [
1174
+ {
1175
+ eventName: "open",
1176
+ invoke: props.onOpen ? (event) => props.onOpen?.(event) : void 0
1177
+ },
1178
+ {
1179
+ eventName: "close",
1180
+ invoke: props.onClose ? (event) => props.onClose?.(event) : void 0
1181
+ },
1182
+ {
1183
+ eventName: "anchorColor_changed",
1184
+ invoke: props.onAnchorColorChanged ? (event) => props.onAnchorColorChanged?.(event) : void 0
1185
+ },
1186
+ {
1187
+ eventName: "anchorSize_changed",
1188
+ invoke: props.onAnchorSizeChanged ? (event) => props.onAnchorSizeChanged?.(event) : void 0
1189
+ },
1190
+ {
1191
+ eventName: "anchorSkew_changed",
1192
+ invoke: props.onAnchorSkewChanged ? (event) => props.onAnchorSkewChanged?.(event) : void 0
1193
+ },
1194
+ {
1195
+ eventName: "backgroundColor_changed",
1196
+ invoke: props.onBackgroundColorChanged ? (event) => props.onBackgroundColorChanged?.(event) : void 0
1197
+ },
1198
+ {
1199
+ eventName: "borderColor_changed",
1200
+ invoke: props.onBorderColorChanged ? (event) => props.onBorderColorChanged?.(event) : void 0
1201
+ },
1202
+ {
1203
+ eventName: "borderWidth_changed",
1204
+ invoke: props.onBorderWidthChanged ? (event) => props.onBorderWidthChanged?.(event) : void 0
1205
+ },
1206
+ {
1207
+ eventName: "content_changed",
1208
+ invoke: props.onContentChanged ? (event) => props.onContentChanged?.(event) : void 0
1209
+ },
1210
+ {
1211
+ eventName: "disableAnchor_changed",
1212
+ invoke: props.onDisableAnchorChanged ? (event) => props.onDisableAnchorChanged?.(event) : void 0
1213
+ },
1214
+ {
1215
+ eventName: "disableAutoPan_changed",
1216
+ invoke: props.onDisableAutoPanChanged ? (event) => props.onDisableAutoPanChanged?.(event) : void 0
1217
+ },
1218
+ {
1219
+ eventName: "maxWidth_changed",
1220
+ invoke: props.onMaxWidthChanged ? (event) => props.onMaxWidthChanged?.(event) : void 0
1221
+ },
1222
+ {
1223
+ eventName: "pixelOffset_changed",
1224
+ invoke: props.onPixelOffsetChanged ? (event) => props.onPixelOffsetChanged?.(event) : void 0
1225
+ },
1226
+ {
1227
+ eventName: "position_changed",
1228
+ invoke: props.onPositionChanged ? (event) => props.onPositionChanged?.(event) : void 0
1229
+ },
1230
+ {
1231
+ eventName: "zIndex_changed",
1232
+ invoke: props.onZIndexChanged ? (event) => props.onZIndexChanged?.(event) : void 0
1233
+ }
1234
+ ];
1235
+ }
1236
+ function bindInfoWindowEventListeners(infoWindow, listenersRef, bindings) {
1237
+ if (listenersRef.current.length > 0) {
1238
+ naver.maps.Event.removeListener(listenersRef.current);
1239
+ listenersRef.current = [];
1240
+ }
1241
+ listenersRef.current = bindings.filter((binding) => typeof binding.invoke === "function").map((binding) => naver.maps.Event.addListener(infoWindow, binding.eventName, (event) => {
1242
+ binding.invoke?.(event);
1243
+ }));
1244
+ }
1245
+ function setInfoWindowOptionByKey(infoWindow, key, value) {
1246
+ infoWindow.setOptions(key, value);
1247
+ }
1248
+ const InfoWindow = forwardRef(function InfoWindowInner(props, ref) {
1249
+ const { map, sdkStatus } = useNaverMap();
1250
+ const infoWindowRef = useRef(null);
1251
+ const infoWindowEventListenersRef = useRef([]);
1252
+ const onInfoWindowDestroyRef = useRef(props.onInfoWindowDestroy);
1253
+ const childrenContainer = useMemo(() => {
1254
+ if (typeof document === "undefined") return null;
1255
+ return document.createElement("div");
1256
+ }, []);
1257
+ const visible = props.visible ?? true;
1258
+ const hasChildren = props.children !== void 0 && props.children !== null;
1259
+ const optionSnapshot = useMemo(() => toInfoWindowOptions(props), [props]);
1260
+ useEffect(() => {
1261
+ onInfoWindowDestroyRef.current = props.onInfoWindowDestroy;
1262
+ }, [props.onInfoWindowDestroy]);
1263
+ const invokeInfoWindowMethod = useCallback((methodName, ...args) => {
1264
+ const infoWindow = infoWindowRef.current;
1265
+ if (!infoWindow) return;
1266
+ const method = infoWindow[methodName];
1267
+ if (typeof method !== "function") return;
1268
+ return method.apply(infoWindow, args);
1269
+ }, []);
1270
+ const teardownInfoWindow = useCallback(() => {
1271
+ const infoWindow = infoWindowRef.current;
1272
+ if (!infoWindow) return;
1273
+ try {
1274
+ if (infoWindowEventListenersRef.current.length > 0) {
1275
+ naver.maps.Event.removeListener(infoWindowEventListenersRef.current);
1276
+ infoWindowEventListenersRef.current = [];
1277
+ }
1278
+ naver.maps.Event.clearInstanceListeners(infoWindow);
1279
+ } catch (error) {
1280
+ console.error("[react-naver-maps-kit] failed to clear infoWindow listeners", error);
1281
+ }
1282
+ infoWindow.close();
1283
+ infoWindow.setMap(null);
1284
+ infoWindowRef.current = null;
1285
+ onInfoWindowDestroyRef.current?.();
1286
+ }, []);
1287
+ useImperativeHandle(ref, () => ({
1288
+ getInstance: () => infoWindowRef.current,
1289
+ close: (...args) => invokeInfoWindowMethod("close", ...args),
1290
+ getContent: (...args) => invokeInfoWindowMethod("getContent", ...args),
1291
+ getContentElement: (...args) => invokeInfoWindowMethod("getContentElement", ...args),
1292
+ getMap: (...args) => invokeInfoWindowMethod("getMap", ...args),
1293
+ getOptions: (...args) => invokeInfoWindowMethod("getOptions", ...args),
1294
+ getPanes: (...args) => invokeInfoWindowMethod("getPanes", ...args),
1295
+ getPosition: (...args) => invokeInfoWindowMethod("getPosition", ...args),
1296
+ getProjection: (...args) => invokeInfoWindowMethod("getProjection", ...args),
1297
+ getZIndex: (...args) => invokeInfoWindowMethod("getZIndex", ...args),
1298
+ open: (...args) => invokeInfoWindowMethod("open", ...args),
1299
+ setContent: (...args) => invokeInfoWindowMethod("setContent", ...args),
1300
+ setMap: (...args) => invokeInfoWindowMethod("setMap", ...args),
1301
+ setOptions: (...args) => invokeInfoWindowMethod("setOptions", ...args),
1302
+ setPosition: (...args) => invokeInfoWindowMethod("setPosition", ...args),
1303
+ setZIndex: (...args) => invokeInfoWindowMethod("setZIndex", ...args)
1304
+ }), [invokeInfoWindowMethod]);
1305
+ useEffect(() => {
1306
+ if (sdkStatus !== "ready" || !map || infoWindowRef.current) return;
1307
+ try {
1308
+ const infoWindow = new naver.maps.InfoWindow({
1309
+ ...optionSnapshot,
1310
+ content: resolveInfoWindowContent(props.content, childrenContainer, hasChildren)
1311
+ });
1312
+ if (props.autoPanPadding !== void 0) setInfoWindowOptionByKey(infoWindow, "autoPanPadding", props.autoPanPadding);
1313
+ infoWindowRef.current = infoWindow;
1314
+ bindInfoWindowEventListeners(infoWindow, infoWindowEventListenersRef, buildInfoWindowEventBindings(props));
1315
+ props.onInfoWindowReady?.(infoWindow);
1316
+ } catch (error) {
1317
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.InfoWindow instance.");
1318
+ props.onInfoWindowError?.(normalizedError);
1319
+ }
1320
+ }, [
1321
+ childrenContainer,
1322
+ hasChildren,
1323
+ map,
1324
+ optionSnapshot,
1325
+ props,
1326
+ sdkStatus
1327
+ ]);
1328
+ useEffect(() => {
1329
+ const infoWindow = infoWindowRef.current;
1330
+ if (!infoWindow) return;
1331
+ const resolvedContent = resolveInfoWindowContent(props.content, childrenContainer, hasChildren);
1332
+ infoWindow.setOptions({
1333
+ ...optionSnapshot,
1334
+ content: resolvedContent
1335
+ });
1336
+ infoWindow.setContent(resolvedContent);
1337
+ if (props.autoPanPadding !== void 0) setInfoWindowOptionByKey(infoWindow, "autoPanPadding", props.autoPanPadding);
1338
+ if (props.position) infoWindow.setPosition(props.position);
1339
+ if (!map || !visible) {
1340
+ infoWindow.close();
1341
+ return;
1342
+ }
1343
+ if (props.anchor) {
1344
+ infoWindow.open(map, props.anchor);
1345
+ return;
1346
+ }
1347
+ if (props.position) {
1348
+ infoWindow.open(map, props.position);
1349
+ return;
1350
+ }
1351
+ infoWindow.open(map);
1352
+ }, [
1353
+ childrenContainer,
1354
+ hasChildren,
1355
+ map,
1356
+ optionSnapshot,
1357
+ props.anchor,
1358
+ props.content,
1359
+ props.position,
1360
+ props.autoPanPadding,
1361
+ visible
1362
+ ]);
1363
+ useEffect(() => {
1364
+ const infoWindow = infoWindowRef.current;
1365
+ if (!infoWindow) return;
1366
+ bindInfoWindowEventListeners(infoWindow, infoWindowEventListenersRef, buildInfoWindowEventBindings(props));
1367
+ return () => {
1368
+ if (infoWindowEventListenersRef.current.length > 0) {
1369
+ naver.maps.Event.removeListener(infoWindowEventListenersRef.current);
1370
+ infoWindowEventListenersRef.current = [];
1371
+ }
1372
+ };
1373
+ }, [props]);
1374
+ useEffect(() => {
1375
+ return () => {
1376
+ teardownInfoWindow();
1377
+ };
1378
+ }, [teardownInfoWindow]);
1379
+ if (!hasChildren || !childrenContainer) return null;
1380
+ return createPortal(props.children, childrenContainer);
1381
+ });
1382
+ InfoWindow.displayName = "InfoWindow";
1383
+
1384
+ //#endregion
1385
+ //#region src/overlays/shared/overlayUtils.ts
1386
+ function bindOverlayEventListeners(target, listenersRef, bindings) {
1387
+ if (listenersRef.current.length > 0) {
1388
+ naver.maps.Event.removeListener(listenersRef.current);
1389
+ listenersRef.current = [];
1390
+ }
1391
+ listenersRef.current = bindings.filter((binding) => typeof binding.invoke === "function").map((binding) => naver.maps.Event.addListener(target, binding.eventName, (event) => {
1392
+ binding.invoke?.(event);
1393
+ }));
1394
+ }
1395
+ function removeOverlayEventListeners(listeners) {
1396
+ if (listeners.length > 0) naver.maps.Event.removeListener(listeners);
1397
+ }
1398
+
1399
+ //#endregion
1400
+ //#region src/overlays/circle/Circle.tsx
1401
+ function toCircleOptions(props, targetMap) {
1402
+ const options = { center: props.center };
1403
+ if (targetMap) options.map = targetMap;
1404
+ if (props.radius !== void 0) options.radius = props.radius;
1405
+ if (props.strokeWeight !== void 0) options.strokeWeight = props.strokeWeight;
1406
+ if (props.strokeOpacity !== void 0) options.strokeOpacity = props.strokeOpacity;
1407
+ if (props.strokeColor !== void 0) options.strokeColor = props.strokeColor;
1408
+ if (props.strokeStyle !== void 0) options.strokeStyle = props.strokeStyle;
1409
+ if (props.strokeLineCap !== void 0) options.strokeLineCap = props.strokeLineCap;
1410
+ if (props.strokeLineJoin !== void 0) options.strokeLineJoin = props.strokeLineJoin;
1411
+ if (props.fillColor !== void 0) options.fillColor = props.fillColor;
1412
+ if (props.fillOpacity !== void 0) options.fillOpacity = props.fillOpacity;
1413
+ if (props.clickable !== void 0) options.clickable = props.clickable;
1414
+ if (props.visible !== void 0) options.visible = props.visible;
1415
+ if (props.zIndex !== void 0) options.zIndex = props.zIndex;
1416
+ return options;
1417
+ }
1418
+ function buildCircleEventBindings(props) {
1419
+ return [
1420
+ {
1421
+ eventName: "click",
1422
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
1423
+ },
1424
+ {
1425
+ eventName: "dblclick",
1426
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
1427
+ },
1428
+ {
1429
+ eventName: "mousedown",
1430
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
1431
+ },
1432
+ {
1433
+ eventName: "mousemove",
1434
+ invoke: props.onMouseMove ? (event) => props.onMouseMove?.(event) : void 0
1435
+ },
1436
+ {
1437
+ eventName: "mouseout",
1438
+ invoke: props.onMouseOut ? (event) => props.onMouseOut?.(event) : void 0
1439
+ },
1440
+ {
1441
+ eventName: "mouseover",
1442
+ invoke: props.onMouseOver ? (event) => props.onMouseOver?.(event) : void 0
1443
+ },
1444
+ {
1445
+ eventName: "mouseup",
1446
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
1447
+ },
1448
+ {
1449
+ eventName: "rightclick",
1450
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
1451
+ },
1452
+ {
1453
+ eventName: "touchstart",
1454
+ invoke: props.onTouchStart ? (event) => props.onTouchStart?.(event) : void 0
1455
+ },
1456
+ {
1457
+ eventName: "touchmove",
1458
+ invoke: props.onTouchMove ? (event) => props.onTouchMove?.(event) : void 0
1459
+ },
1460
+ {
1461
+ eventName: "touchend",
1462
+ invoke: props.onTouchEnd ? (event) => props.onTouchEnd?.(event) : void 0
1463
+ },
1464
+ {
1465
+ eventName: "center_changed",
1466
+ invoke: props.onCenterChanged ? (event) => props.onCenterChanged?.(event) : void 0
1467
+ },
1468
+ {
1469
+ eventName: "clickable_changed",
1470
+ invoke: props.onClickableChanged ? (event) => props.onClickableChanged?.(event) : void 0
1471
+ },
1472
+ {
1473
+ eventName: "fillColor_changed",
1474
+ invoke: props.onFillColorChanged ? (event) => props.onFillColorChanged?.(event) : void 0
1475
+ },
1476
+ {
1477
+ eventName: "fillOpacity_changed",
1478
+ invoke: props.onFillOpacityChanged ? (event) => props.onFillOpacityChanged?.(event) : void 0
1479
+ },
1480
+ {
1481
+ eventName: "map_changed",
1482
+ invoke: props.onMapChanged ? (event) => props.onMapChanged?.(event) : void 0
1483
+ },
1484
+ {
1485
+ eventName: "radius_changed",
1486
+ invoke: props.onRadiusChanged ? (event) => props.onRadiusChanged?.(event) : void 0
1487
+ },
1488
+ {
1489
+ eventName: "strokeColor_changed",
1490
+ invoke: props.onStrokeColorChanged ? (event) => props.onStrokeColorChanged?.(event) : void 0
1491
+ },
1492
+ {
1493
+ eventName: "strokeLineCap_changed",
1494
+ invoke: props.onStrokeLineCapChanged ? (event) => props.onStrokeLineCapChanged?.(event) : void 0
1495
+ },
1496
+ {
1497
+ eventName: "strokeLineJoin_changed",
1498
+ invoke: props.onStrokeLineJoinChanged ? (event) => props.onStrokeLineJoinChanged?.(event) : void 0
1499
+ },
1500
+ {
1501
+ eventName: "strokeOpacity_changed",
1502
+ invoke: props.onStrokeOpacityChanged ? (event) => props.onStrokeOpacityChanged?.(event) : void 0
1503
+ },
1504
+ {
1505
+ eventName: "strokeStyle_changed",
1506
+ invoke: props.onStrokeStyleChanged ? (event) => props.onStrokeStyleChanged?.(event) : void 0
1507
+ },
1508
+ {
1509
+ eventName: "strokeWeight_changed",
1510
+ invoke: props.onStrokeWeightChanged ? (event) => props.onStrokeWeightChanged?.(event) : void 0
1511
+ },
1512
+ {
1513
+ eventName: "visible_changed",
1514
+ invoke: props.onVisibleChanged ? (event) => props.onVisibleChanged?.(event) : void 0
1515
+ },
1516
+ {
1517
+ eventName: "zIndex_changed",
1518
+ invoke: props.onZIndexChanged ? (event) => props.onZIndexChanged?.(event) : void 0
1519
+ }
1520
+ ];
1521
+ }
1522
+ const Circle = forwardRef(function CircleInner(props, ref) {
1523
+ const { map: contextMap, sdkStatus } = useNaverMap();
1524
+ const circleRef = useRef(null);
1525
+ const circleEventListenersRef = useRef([]);
1526
+ const onCircleDestroyRef = useRef(props.onCircleDestroy);
1527
+ const targetMap = props.map ?? contextMap;
1528
+ useEffect(() => {
1529
+ onCircleDestroyRef.current = props.onCircleDestroy;
1530
+ }, [props.onCircleDestroy]);
1531
+ const invokeCircleMethod = useCallback((methodName, ...args) => {
1532
+ const circle = circleRef.current;
1533
+ if (!circle) return;
1534
+ const method = circle[methodName];
1535
+ if (typeof method !== "function") return;
1536
+ return method.apply(circle, args);
1537
+ }, []);
1538
+ const teardownCircle = useCallback(() => {
1539
+ const circle = circleRef.current;
1540
+ if (!circle) return;
1541
+ try {
1542
+ removeOverlayEventListeners(circleEventListenersRef.current);
1543
+ circleEventListenersRef.current = [];
1544
+ naver.maps.Event.clearInstanceListeners(circle);
1545
+ } catch (error) {
1546
+ console.error("[react-naver-maps-kit] failed to clear circle listeners", error);
1547
+ }
1548
+ circle.setMap(null);
1549
+ circleRef.current = null;
1550
+ onCircleDestroyRef.current?.();
1551
+ }, []);
1552
+ useImperativeHandle(ref, () => ({
1553
+ getInstance: () => circleRef.current,
1554
+ getAreaSize: (...args) => invokeCircleMethod("getAreaSize", ...args),
1555
+ getBounds: (...args) => invokeCircleMethod("getBounds", ...args),
1556
+ getCenter: (...args) => invokeCircleMethod("getCenter", ...args),
1557
+ getClickable: (...args) => invokeCircleMethod("getClickable", ...args),
1558
+ getDrawingRect: (...args) => invokeCircleMethod("getDrawingRect", ...args),
1559
+ getElement: (...args) => invokeCircleMethod("getElement", ...args),
1560
+ getMap: (...args) => invokeCircleMethod("getMap", ...args),
1561
+ getOptions: (...args) => invokeCircleMethod("getOptions", ...args),
1562
+ getPanes: (...args) => invokeCircleMethod("getPanes", ...args),
1563
+ getProjection: (...args) => invokeCircleMethod("getProjection", ...args),
1564
+ getRadius: (...args) => invokeCircleMethod("getRadius", ...args),
1565
+ getStyles: (...args) => invokeCircleMethod("getStyles", ...args),
1566
+ getVisible: (...args) => invokeCircleMethod("getVisible", ...args),
1567
+ getZIndex: (...args) => invokeCircleMethod("getZIndex", ...args),
1568
+ setCenter: (...args) => invokeCircleMethod("setCenter", ...args),
1569
+ setClickable: (...args) => invokeCircleMethod("setClickable", ...args),
1570
+ setMap: (...args) => invokeCircleMethod("setMap", ...args),
1571
+ setOptions: (...args) => invokeCircleMethod("setOptions", ...args),
1572
+ setRadius: (...args) => invokeCircleMethod("setRadius", ...args),
1573
+ setStyles: (...args) => invokeCircleMethod("setStyles", ...args),
1574
+ setVisible: (...args) => invokeCircleMethod("setVisible", ...args),
1575
+ setZIndex: (...args) => invokeCircleMethod("setZIndex", ...args)
1576
+ }), [invokeCircleMethod]);
1577
+ useEffect(() => {
1578
+ if (sdkStatus !== "ready" || !targetMap || circleRef.current) return;
1579
+ try {
1580
+ const circle = new naver.maps.Circle(toCircleOptions(props, targetMap));
1581
+ circleRef.current = circle;
1582
+ bindOverlayEventListeners(circle, circleEventListenersRef, buildCircleEventBindings(props));
1583
+ props.onCircleReady?.(circle);
1584
+ } catch (error) {
1585
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Circle instance.");
1586
+ props.onCircleError?.(normalizedError);
1587
+ }
1588
+ }, [
1589
+ props,
1590
+ sdkStatus,
1591
+ targetMap
1592
+ ]);
1593
+ useEffect(() => {
1594
+ const circle = circleRef.current;
1595
+ if (!circle || !targetMap) return;
1596
+ circle.setOptions(toCircleOptions(props, targetMap));
1597
+ }, [props, targetMap]);
1598
+ useEffect(() => {
1599
+ const circle = circleRef.current;
1600
+ if (!circle) return;
1601
+ bindOverlayEventListeners(circle, circleEventListenersRef, buildCircleEventBindings(props));
1602
+ return () => {
1603
+ removeOverlayEventListeners(circleEventListenersRef.current);
1604
+ circleEventListenersRef.current = [];
1605
+ };
1606
+ }, [props]);
1607
+ useEffect(() => {
1608
+ return () => {
1609
+ teardownCircle();
1610
+ };
1611
+ }, [teardownCircle]);
1612
+ return null;
1613
+ });
1614
+ Circle.displayName = "Circle";
1615
+
1616
+ //#endregion
1617
+ //#region src/overlays/ellipse/Ellipse.tsx
1618
+ function toEllipseOptions(props, targetMap) {
1619
+ const options = { bounds: props.bounds };
1620
+ if (targetMap) options.map = targetMap;
1621
+ if (props.strokeWeight !== void 0) options.strokeWeight = props.strokeWeight;
1622
+ if (props.strokeOpacity !== void 0) options.strokeOpacity = props.strokeOpacity;
1623
+ if (props.strokeColor !== void 0) options.strokeColor = props.strokeColor;
1624
+ if (props.strokeStyle !== void 0) options.strokeStyle = props.strokeStyle;
1625
+ if (props.strokeLineCap !== void 0) options.strokeLineCap = props.strokeLineCap;
1626
+ if (props.strokeLineJoin !== void 0) options.strokeLineJoin = props.strokeLineJoin;
1627
+ if (props.fillColor !== void 0) options.fillColor = props.fillColor;
1628
+ if (props.fillOpacity !== void 0) options.fillOpacity = props.fillOpacity;
1629
+ if (props.clickable !== void 0) options.clickable = props.clickable;
1630
+ if (props.visible !== void 0) options.visible = props.visible;
1631
+ if (props.zIndex !== void 0) options.zIndex = props.zIndex;
1632
+ return options;
1633
+ }
1634
+ function buildEllipseEventBindings(props) {
1635
+ return [
1636
+ {
1637
+ eventName: "click",
1638
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
1639
+ },
1640
+ {
1641
+ eventName: "dblclick",
1642
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
1643
+ },
1644
+ {
1645
+ eventName: "mousedown",
1646
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
1647
+ },
1648
+ {
1649
+ eventName: "mousemove",
1650
+ invoke: props.onMouseMove ? (event) => props.onMouseMove?.(event) : void 0
1651
+ },
1652
+ {
1653
+ eventName: "mouseout",
1654
+ invoke: props.onMouseOut ? (event) => props.onMouseOut?.(event) : void 0
1655
+ },
1656
+ {
1657
+ eventName: "mouseover",
1658
+ invoke: props.onMouseOver ? (event) => props.onMouseOver?.(event) : void 0
1659
+ },
1660
+ {
1661
+ eventName: "mouseup",
1662
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
1663
+ },
1664
+ {
1665
+ eventName: "rightclick",
1666
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
1667
+ },
1668
+ {
1669
+ eventName: "touchstart",
1670
+ invoke: props.onTouchStart ? (event) => props.onTouchStart?.(event) : void 0
1671
+ },
1672
+ {
1673
+ eventName: "touchmove",
1674
+ invoke: props.onTouchMove ? (event) => props.onTouchMove?.(event) : void 0
1675
+ },
1676
+ {
1677
+ eventName: "touchend",
1678
+ invoke: props.onTouchEnd ? (event) => props.onTouchEnd?.(event) : void 0
1679
+ },
1680
+ {
1681
+ eventName: "bounds_changed",
1682
+ invoke: props.onBoundsChanged ? (event) => props.onBoundsChanged?.(event) : void 0
1683
+ },
1684
+ {
1685
+ eventName: "clickable_changed",
1686
+ invoke: props.onClickableChanged ? (event) => props.onClickableChanged?.(event) : void 0
1687
+ },
1688
+ {
1689
+ eventName: "fillColor_changed",
1690
+ invoke: props.onFillColorChanged ? (event) => props.onFillColorChanged?.(event) : void 0
1691
+ },
1692
+ {
1693
+ eventName: "fillOpacity_changed",
1694
+ invoke: props.onFillOpacityChanged ? (event) => props.onFillOpacityChanged?.(event) : void 0
1695
+ },
1696
+ {
1697
+ eventName: "map_changed",
1698
+ invoke: props.onMapChanged ? (event) => props.onMapChanged?.(event) : void 0
1699
+ },
1700
+ {
1701
+ eventName: "strokeColor_changed",
1702
+ invoke: props.onStrokeColorChanged ? (event) => props.onStrokeColorChanged?.(event) : void 0
1703
+ },
1704
+ {
1705
+ eventName: "strokeLineCap_changed",
1706
+ invoke: props.onStrokeLineCapChanged ? (event) => props.onStrokeLineCapChanged?.(event) : void 0
1707
+ },
1708
+ {
1709
+ eventName: "strokeLineJoin_changed",
1710
+ invoke: props.onStrokeLineJoinChanged ? (event) => props.onStrokeLineJoinChanged?.(event) : void 0
1711
+ },
1712
+ {
1713
+ eventName: "strokeOpacity_changed",
1714
+ invoke: props.onStrokeOpacityChanged ? (event) => props.onStrokeOpacityChanged?.(event) : void 0
1715
+ },
1716
+ {
1717
+ eventName: "strokeStyle_changed",
1718
+ invoke: props.onStrokeStyleChanged ? (event) => props.onStrokeStyleChanged?.(event) : void 0
1719
+ },
1720
+ {
1721
+ eventName: "strokeWeight_changed",
1722
+ invoke: props.onStrokeWeightChanged ? (event) => props.onStrokeWeightChanged?.(event) : void 0
1723
+ },
1724
+ {
1725
+ eventName: "visible_changed",
1726
+ invoke: props.onVisibleChanged ? (event) => props.onVisibleChanged?.(event) : void 0
1727
+ },
1728
+ {
1729
+ eventName: "zIndex_changed",
1730
+ invoke: props.onZIndexChanged ? (event) => props.onZIndexChanged?.(event) : void 0
1731
+ }
1732
+ ];
1733
+ }
1734
+ const Ellipse = forwardRef(function EllipseInner(props, ref) {
1735
+ const { map: contextMap, sdkStatus } = useNaverMap();
1736
+ const ellipseRef = useRef(null);
1737
+ const ellipseEventListenersRef = useRef([]);
1738
+ const onEllipseDestroyRef = useRef(props.onEllipseDestroy);
1739
+ const targetMap = props.map ?? contextMap;
1740
+ useEffect(() => {
1741
+ onEllipseDestroyRef.current = props.onEllipseDestroy;
1742
+ }, [props.onEllipseDestroy]);
1743
+ const invokeEllipseMethod = useCallback((methodName, ...args) => {
1744
+ const ellipse = ellipseRef.current;
1745
+ if (!ellipse) return;
1746
+ const method = ellipse[methodName];
1747
+ if (typeof method !== "function") return;
1748
+ return method.apply(ellipse, args);
1749
+ }, []);
1750
+ const teardownEllipse = useCallback(() => {
1751
+ const ellipse = ellipseRef.current;
1752
+ if (!ellipse) return;
1753
+ try {
1754
+ removeOverlayEventListeners(ellipseEventListenersRef.current);
1755
+ ellipseEventListenersRef.current = [];
1756
+ naver.maps.Event.clearInstanceListeners(ellipse);
1757
+ } catch (error) {
1758
+ console.error("[react-naver-maps-kit] failed to clear ellipse listeners", error);
1759
+ }
1760
+ ellipse.setMap(null);
1761
+ ellipseRef.current = null;
1762
+ onEllipseDestroyRef.current?.();
1763
+ }, []);
1764
+ useImperativeHandle(ref, () => ({
1765
+ getInstance: () => ellipseRef.current,
1766
+ getAreaSize: (...args) => invokeEllipseMethod("getAreaSize", ...args),
1767
+ getBounds: (...args) => invokeEllipseMethod("getBounds", ...args),
1768
+ getClickable: (...args) => invokeEllipseMethod("getClickable", ...args),
1769
+ getDrawingRect: (...args) => invokeEllipseMethod("getDrawingRect", ...args),
1770
+ getElement: (...args) => invokeEllipseMethod("getElement", ...args),
1771
+ getMap: (...args) => invokeEllipseMethod("getMap", ...args),
1772
+ getOptions: (...args) => invokeEllipseMethod("getOptions", ...args),
1773
+ getPanes: (...args) => invokeEllipseMethod("getPanes", ...args),
1774
+ getProjection: (...args) => invokeEllipseMethod("getProjection", ...args),
1775
+ getStyles: (...args) => invokeEllipseMethod("getStyles", ...args),
1776
+ getVisible: (...args) => invokeEllipseMethod("getVisible", ...args),
1777
+ getZIndex: (...args) => invokeEllipseMethod("getZIndex", ...args),
1778
+ setBounds: (...args) => invokeEllipseMethod("setBounds", ...args),
1779
+ setClickable: (...args) => invokeEllipseMethod("setClickable", ...args),
1780
+ setMap: (...args) => invokeEllipseMethod("setMap", ...args),
1781
+ setOptions: (...args) => invokeEllipseMethod("setOptions", ...args),
1782
+ setStyles: (...args) => invokeEllipseMethod("setStyles", ...args),
1783
+ setVisible: (...args) => invokeEllipseMethod("setVisible", ...args),
1784
+ setZIndex: (...args) => invokeEllipseMethod("setZIndex", ...args)
1785
+ }), [invokeEllipseMethod]);
1786
+ useEffect(() => {
1787
+ if (sdkStatus !== "ready" || !targetMap || ellipseRef.current) return;
1788
+ try {
1789
+ const ellipse = new naver.maps.Ellipse(toEllipseOptions(props, targetMap));
1790
+ ellipseRef.current = ellipse;
1791
+ bindOverlayEventListeners(ellipse, ellipseEventListenersRef, buildEllipseEventBindings(props));
1792
+ props.onEllipseReady?.(ellipse);
1793
+ } catch (error) {
1794
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Ellipse instance.");
1795
+ props.onEllipseError?.(normalizedError);
1796
+ }
1797
+ }, [
1798
+ props,
1799
+ sdkStatus,
1800
+ targetMap
1801
+ ]);
1802
+ useEffect(() => {
1803
+ const ellipse = ellipseRef.current;
1804
+ if (!ellipse || !targetMap) return;
1805
+ ellipse.setOptions(toEllipseOptions(props, targetMap));
1806
+ }, [props, targetMap]);
1807
+ useEffect(() => {
1808
+ const ellipse = ellipseRef.current;
1809
+ if (!ellipse) return;
1810
+ bindOverlayEventListeners(ellipse, ellipseEventListenersRef, buildEllipseEventBindings(props));
1811
+ return () => {
1812
+ removeOverlayEventListeners(ellipseEventListenersRef.current);
1813
+ ellipseEventListenersRef.current = [];
1814
+ };
1815
+ }, [props]);
1816
+ useEffect(() => {
1817
+ return () => {
1818
+ teardownEllipse();
1819
+ };
1820
+ }, [teardownEllipse]);
1821
+ return null;
1822
+ });
1823
+ Ellipse.displayName = "Ellipse";
1824
+
1825
+ //#endregion
1826
+ //#region src/overlays/ground-overlay/GroundOverlay.tsx
1827
+ function toGroundOverlayOptions(props, targetMap) {
1828
+ const options = {};
1829
+ if (targetMap) options.map = targetMap;
1830
+ if (props.clickable !== void 0) options.clickable = props.clickable;
1831
+ if (props.opacity !== void 0) options.opacity = props.opacity;
1832
+ return options;
1833
+ }
1834
+ function buildGroundOverlayEventBindings(props) {
1835
+ return [
1836
+ {
1837
+ eventName: "click",
1838
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
1839
+ },
1840
+ {
1841
+ eventName: "dblclick",
1842
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
1843
+ },
1844
+ {
1845
+ eventName: "mousedown",
1846
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
1847
+ },
1848
+ {
1849
+ eventName: "mousemove",
1850
+ invoke: props.onMouseMove ? (event) => props.onMouseMove?.(event) : void 0
1851
+ },
1852
+ {
1853
+ eventName: "mouseout",
1854
+ invoke: props.onMouseOut ? (event) => props.onMouseOut?.(event) : void 0
1855
+ },
1856
+ {
1857
+ eventName: "mouseover",
1858
+ invoke: props.onMouseOver ? (event) => props.onMouseOver?.(event) : void 0
1859
+ },
1860
+ {
1861
+ eventName: "mouseup",
1862
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
1863
+ },
1864
+ {
1865
+ eventName: "rightclick",
1866
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
1867
+ },
1868
+ {
1869
+ eventName: "touchstart",
1870
+ invoke: props.onTouchStart ? (event) => props.onTouchStart?.(event) : void 0
1871
+ },
1872
+ {
1873
+ eventName: "touchmove",
1874
+ invoke: props.onTouchMove ? (event) => props.onTouchMove?.(event) : void 0
1875
+ },
1876
+ {
1877
+ eventName: "touchend",
1878
+ invoke: props.onTouchEnd ? (event) => props.onTouchEnd?.(event) : void 0
1879
+ },
1880
+ {
1881
+ eventName: "bounds_changed",
1882
+ invoke: props.onBoundsChanged ? (event) => props.onBoundsChanged?.(event) : void 0
1883
+ },
1884
+ {
1885
+ eventName: "clickable_changed",
1886
+ invoke: props.onClickableChanged ? (event) => props.onClickableChanged?.(event) : void 0
1887
+ },
1888
+ {
1889
+ eventName: "map_changed",
1890
+ invoke: props.onMapChanged ? (event) => props.onMapChanged?.(event) : void 0
1891
+ },
1892
+ {
1893
+ eventName: "opacity_changed",
1894
+ invoke: props.onOpacityChanged ? (event) => props.onOpacityChanged?.(event) : void 0
1895
+ }
1896
+ ];
1897
+ }
1898
+ const GroundOverlay = forwardRef(function GroundOverlayInner(props, ref) {
1899
+ const { map: contextMap, sdkStatus } = useNaverMap();
1900
+ const groundOverlayRef = useRef(null);
1901
+ const groundOverlayEventListenersRef = useRef([]);
1902
+ const onGroundOverlayDestroyRef = useRef(props.onGroundOverlayDestroy);
1903
+ const targetMap = props.map ?? contextMap;
1904
+ useEffect(() => {
1905
+ onGroundOverlayDestroyRef.current = props.onGroundOverlayDestroy;
1906
+ }, [props.onGroundOverlayDestroy]);
1907
+ const invokeGroundOverlayMethod = useCallback((methodName, ...args) => {
1908
+ const groundOverlay = groundOverlayRef.current;
1909
+ if (!groundOverlay) return;
1910
+ const method = groundOverlay[methodName];
1911
+ if (typeof method !== "function") return;
1912
+ return method.apply(groundOverlay, args);
1913
+ }, []);
1914
+ const teardownGroundOverlay = useCallback(() => {
1915
+ const groundOverlay = groundOverlayRef.current;
1916
+ if (!groundOverlay) return;
1917
+ try {
1918
+ removeOverlayEventListeners(groundOverlayEventListenersRef.current);
1919
+ groundOverlayEventListenersRef.current = [];
1920
+ naver.maps.Event.clearInstanceListeners(groundOverlay);
1921
+ } catch (error) {
1922
+ console.error("[react-naver-maps-kit] failed to clear ground overlay listeners", error);
1923
+ }
1924
+ groundOverlay.setMap(null);
1925
+ groundOverlayRef.current = null;
1926
+ onGroundOverlayDestroyRef.current?.();
1927
+ }, []);
1928
+ useImperativeHandle(ref, () => ({
1929
+ getInstance: () => groundOverlayRef.current,
1930
+ getBounds: (...args) => invokeGroundOverlayMethod("getBounds", ...args),
1931
+ getMap: (...args) => invokeGroundOverlayMethod("getMap", ...args),
1932
+ getOpacity: (...args) => invokeGroundOverlayMethod("getOpacity", ...args),
1933
+ getPanes: (...args) => invokeGroundOverlayMethod("getPanes", ...args),
1934
+ getProjection: (...args) => invokeGroundOverlayMethod("getProjection", ...args),
1935
+ getUrl: (...args) => invokeGroundOverlayMethod("getUrl", ...args),
1936
+ setMap: (...args) => invokeGroundOverlayMethod("setMap", ...args),
1937
+ setOpacity: (...args) => invokeGroundOverlayMethod("setOpacity", ...args)
1938
+ }), [invokeGroundOverlayMethod]);
1939
+ useEffect(() => {
1940
+ if (sdkStatus !== "ready" || !targetMap || groundOverlayRef.current) return;
1941
+ try {
1942
+ const groundOverlay = new naver.maps.GroundOverlay(props.url, props.bounds, toGroundOverlayOptions(props, targetMap));
1943
+ groundOverlayRef.current = groundOverlay;
1944
+ bindOverlayEventListeners(groundOverlay, groundOverlayEventListenersRef, buildGroundOverlayEventBindings(props));
1945
+ props.onGroundOverlayReady?.(groundOverlay);
1946
+ } catch (error) {
1947
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.GroundOverlay instance.");
1948
+ props.onGroundOverlayError?.(normalizedError);
1949
+ }
1950
+ }, [
1951
+ props,
1952
+ sdkStatus,
1953
+ targetMap
1954
+ ]);
1955
+ useEffect(() => {
1956
+ const groundOverlay = groundOverlayRef.current;
1957
+ if (!groundOverlay || !targetMap) return;
1958
+ groundOverlay.setMap(targetMap);
1959
+ if (props.opacity !== void 0) groundOverlay.setOpacity(props.opacity);
1960
+ groundOverlay.setOptions?.(toGroundOverlayOptions(props, targetMap));
1961
+ }, [props, targetMap]);
1962
+ useEffect(() => {
1963
+ const groundOverlay = groundOverlayRef.current;
1964
+ if (!groundOverlay) return;
1965
+ bindOverlayEventListeners(groundOverlay, groundOverlayEventListenersRef, buildGroundOverlayEventBindings(props));
1966
+ return () => {
1967
+ removeOverlayEventListeners(groundOverlayEventListenersRef.current);
1968
+ groundOverlayEventListenersRef.current = [];
1969
+ };
1970
+ }, [props]);
1971
+ useEffect(() => {
1972
+ return () => {
1973
+ teardownGroundOverlay();
1974
+ };
1975
+ }, [teardownGroundOverlay]);
1976
+ return null;
1977
+ });
1978
+ GroundOverlay.displayName = "GroundOverlay";
1979
+
1980
+ //#endregion
1981
+ //#region src/overlays/polygon/Polygon.tsx
1982
+ function toPolygonOptions(props, targetMap) {
1983
+ const options = { paths: props.paths };
1984
+ if (targetMap) options.map = targetMap;
1985
+ if (props.strokeWeight !== void 0) options.strokeWeight = props.strokeWeight;
1986
+ if (props.strokeOpacity !== void 0) options.strokeOpacity = props.strokeOpacity;
1987
+ if (props.strokeColor !== void 0) options.strokeColor = props.strokeColor;
1988
+ if (props.strokeStyle !== void 0) options.strokeStyle = props.strokeStyle;
1989
+ if (props.strokeLineCap !== void 0) options.strokeLineCap = props.strokeLineCap;
1990
+ if (props.strokeLineJoin !== void 0) options.strokeLineJoin = props.strokeLineJoin;
1991
+ if (props.fillColor !== void 0) options.fillColor = props.fillColor;
1992
+ if (props.fillOpacity !== void 0) options.fillOpacity = props.fillOpacity;
1993
+ if (props.clickable !== void 0) options.clickable = props.clickable;
1994
+ if (props.visible !== void 0) options.visible = props.visible;
1995
+ if (props.zIndex !== void 0) options.zIndex = props.zIndex;
1996
+ return options;
1997
+ }
1998
+ function buildPolygonEventBindings(props) {
1999
+ return [
2000
+ {
2001
+ eventName: "click",
2002
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
2003
+ },
2004
+ {
2005
+ eventName: "dblclick",
2006
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
2007
+ },
2008
+ {
2009
+ eventName: "mousedown",
2010
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
2011
+ },
2012
+ {
2013
+ eventName: "mousemove",
2014
+ invoke: props.onMouseMove ? (event) => props.onMouseMove?.(event) : void 0
2015
+ },
2016
+ {
2017
+ eventName: "mouseout",
2018
+ invoke: props.onMouseOut ? (event) => props.onMouseOut?.(event) : void 0
2019
+ },
2020
+ {
2021
+ eventName: "mouseover",
2022
+ invoke: props.onMouseOver ? (event) => props.onMouseOver?.(event) : void 0
2023
+ },
2024
+ {
2025
+ eventName: "mouseup",
2026
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
2027
+ },
2028
+ {
2029
+ eventName: "rightclick",
2030
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
2031
+ },
2032
+ {
2033
+ eventName: "touchstart",
2034
+ invoke: props.onTouchStart ? (event) => props.onTouchStart?.(event) : void 0
2035
+ },
2036
+ {
2037
+ eventName: "touchmove",
2038
+ invoke: props.onTouchMove ? (event) => props.onTouchMove?.(event) : void 0
2039
+ },
2040
+ {
2041
+ eventName: "touchend",
2042
+ invoke: props.onTouchEnd ? (event) => props.onTouchEnd?.(event) : void 0
2043
+ },
2044
+ {
2045
+ eventName: "clickable_changed",
2046
+ invoke: props.onClickableChanged ? (event) => props.onClickableChanged?.(event) : void 0
2047
+ },
2048
+ {
2049
+ eventName: "fillColor_changed",
2050
+ invoke: props.onFillColorChanged ? (event) => props.onFillColorChanged?.(event) : void 0
2051
+ },
2052
+ {
2053
+ eventName: "fillOpacity_changed",
2054
+ invoke: props.onFillOpacityChanged ? (event) => props.onFillOpacityChanged?.(event) : void 0
2055
+ },
2056
+ {
2057
+ eventName: "map_changed",
2058
+ invoke: props.onMapChanged ? (event) => props.onMapChanged?.(event) : void 0
2059
+ },
2060
+ {
2061
+ eventName: "path_changed",
2062
+ invoke: props.onPathChanged ? (event) => props.onPathChanged?.(event) : void 0
2063
+ },
2064
+ {
2065
+ eventName: "paths_changed",
2066
+ invoke: props.onPathsChanged ? (event) => props.onPathsChanged?.(event) : void 0
2067
+ },
2068
+ {
2069
+ eventName: "strokeColor_changed",
2070
+ invoke: props.onStrokeColorChanged ? (event) => props.onStrokeColorChanged?.(event) : void 0
2071
+ },
2072
+ {
2073
+ eventName: "strokeLineCap_changed",
2074
+ invoke: props.onStrokeLineCapChanged ? (event) => props.onStrokeLineCapChanged?.(event) : void 0
2075
+ },
2076
+ {
2077
+ eventName: "strokeLineJoin_changed",
2078
+ invoke: props.onStrokeLineJoinChanged ? (event) => props.onStrokeLineJoinChanged?.(event) : void 0
2079
+ },
2080
+ {
2081
+ eventName: "strokeOpacity_changed",
2082
+ invoke: props.onStrokeOpacityChanged ? (event) => props.onStrokeOpacityChanged?.(event) : void 0
2083
+ },
2084
+ {
2085
+ eventName: "strokeStyle_changed",
2086
+ invoke: props.onStrokeStyleChanged ? (event) => props.onStrokeStyleChanged?.(event) : void 0
2087
+ },
2088
+ {
2089
+ eventName: "strokeWeight_changed",
2090
+ invoke: props.onStrokeWeightChanged ? (event) => props.onStrokeWeightChanged?.(event) : void 0
2091
+ },
2092
+ {
2093
+ eventName: "visible_changed",
2094
+ invoke: props.onVisibleChanged ? (event) => props.onVisibleChanged?.(event) : void 0
2095
+ },
2096
+ {
2097
+ eventName: "zIndex_changed",
2098
+ invoke: props.onZIndexChanged ? (event) => props.onZIndexChanged?.(event) : void 0
2099
+ }
2100
+ ];
2101
+ }
2102
+ const Polygon = forwardRef(function PolygonInner(props, ref) {
2103
+ const { map: contextMap, sdkStatus } = useNaverMap();
2104
+ const polygonRef = useRef(null);
2105
+ const polygonEventListenersRef = useRef([]);
2106
+ const onPolygonDestroyRef = useRef(props.onPolygonDestroy);
2107
+ const targetMap = props.map ?? contextMap;
2108
+ useEffect(() => {
2109
+ onPolygonDestroyRef.current = props.onPolygonDestroy;
2110
+ }, [props.onPolygonDestroy]);
2111
+ const invokePolygonMethod = useCallback((methodName, ...args) => {
2112
+ const polygon = polygonRef.current;
2113
+ if (!polygon) return;
2114
+ const method = polygon[methodName];
2115
+ if (typeof method !== "function") return;
2116
+ return method.apply(polygon, args);
2117
+ }, []);
2118
+ const teardownPolygon = useCallback(() => {
2119
+ const polygon = polygonRef.current;
2120
+ if (!polygon) return;
2121
+ try {
2122
+ removeOverlayEventListeners(polygonEventListenersRef.current);
2123
+ polygonEventListenersRef.current = [];
2124
+ naver.maps.Event.clearInstanceListeners(polygon);
2125
+ } catch (error) {
2126
+ console.error("[react-naver-maps-kit] failed to clear polygon listeners", error);
2127
+ }
2128
+ polygon.setMap(null);
2129
+ polygonRef.current = null;
2130
+ onPolygonDestroyRef.current?.();
2131
+ }, []);
2132
+ useImperativeHandle(ref, () => ({
2133
+ getInstance: () => polygonRef.current,
2134
+ getAreaSize: (...args) => invokePolygonMethod("getAreaSize", ...args),
2135
+ getBounds: (...args) => invokePolygonMethod("getBounds", ...args),
2136
+ getClickable: (...args) => invokePolygonMethod("getClickable", ...args),
2137
+ getDrawingRect: (...args) => invokePolygonMethod("getDrawingRect", ...args),
2138
+ getElement: (...args) => invokePolygonMethod("getElement", ...args),
2139
+ getMap: (...args) => invokePolygonMethod("getMap", ...args),
2140
+ getOptions: (...args) => invokePolygonMethod("getOptions", ...args),
2141
+ getPanes: (...args) => invokePolygonMethod("getPanes", ...args),
2142
+ getPath: (...args) => invokePolygonMethod("getPath", ...args),
2143
+ getPaths: (...args) => invokePolygonMethod("getPaths", ...args),
2144
+ getProjection: (...args) => invokePolygonMethod("getProjection", ...args),
2145
+ getStyles: (...args) => invokePolygonMethod("getStyles", ...args),
2146
+ getVisible: (...args) => invokePolygonMethod("getVisible", ...args),
2147
+ getZIndex: (...args) => invokePolygonMethod("getZIndex", ...args),
2148
+ setClickable: (...args) => invokePolygonMethod("setClickable", ...args),
2149
+ setMap: (...args) => invokePolygonMethod("setMap", ...args),
2150
+ setOptions: (...args) => invokePolygonMethod("setOptions", ...args),
2151
+ setPath: (...args) => invokePolygonMethod("setPath", ...args),
2152
+ setPaths: (...args) => invokePolygonMethod("setPaths", ...args),
2153
+ setStyles: (...args) => invokePolygonMethod("setStyles", ...args),
2154
+ setVisible: (...args) => invokePolygonMethod("setVisible", ...args),
2155
+ setZIndex: (...args) => invokePolygonMethod("setZIndex", ...args)
2156
+ }), [invokePolygonMethod]);
2157
+ useEffect(() => {
2158
+ if (sdkStatus !== "ready" || !targetMap || polygonRef.current) return;
2159
+ try {
2160
+ const polygon = new naver.maps.Polygon(toPolygonOptions(props, targetMap));
2161
+ polygonRef.current = polygon;
2162
+ bindOverlayEventListeners(polygon, polygonEventListenersRef, buildPolygonEventBindings(props));
2163
+ props.onPolygonReady?.(polygon);
2164
+ } catch (error) {
2165
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Polygon instance.");
2166
+ props.onPolygonError?.(normalizedError);
2167
+ }
2168
+ }, [
2169
+ props,
2170
+ sdkStatus,
2171
+ targetMap
2172
+ ]);
2173
+ useEffect(() => {
2174
+ const polygon = polygonRef.current;
2175
+ if (!polygon || !targetMap) return;
2176
+ polygon.setOptions(toPolygonOptions(props, targetMap));
2177
+ }, [props, targetMap]);
2178
+ useEffect(() => {
2179
+ const polygon = polygonRef.current;
2180
+ if (!polygon) return;
2181
+ bindOverlayEventListeners(polygon, polygonEventListenersRef, buildPolygonEventBindings(props));
2182
+ return () => {
2183
+ removeOverlayEventListeners(polygonEventListenersRef.current);
2184
+ polygonEventListenersRef.current = [];
2185
+ };
2186
+ }, [props]);
2187
+ useEffect(() => {
2188
+ return () => {
2189
+ teardownPolygon();
2190
+ };
2191
+ }, [teardownPolygon]);
2192
+ return null;
2193
+ });
2194
+ Polygon.displayName = "Polygon";
2195
+
2196
+ //#endregion
2197
+ //#region src/overlays/polyline/Polyline.tsx
2198
+ function toPolylineOptions(props, targetMap) {
2199
+ const options = { path: props.path };
2200
+ if (targetMap) options.map = targetMap;
2201
+ if (props.strokeWeight !== void 0) options.strokeWeight = props.strokeWeight;
2202
+ if (props.strokeOpacity !== void 0) options.strokeOpacity = props.strokeOpacity;
2203
+ if (props.strokeColor !== void 0) options.strokeColor = props.strokeColor;
2204
+ if (props.strokeStyle !== void 0) options.strokeStyle = props.strokeStyle;
2205
+ if (props.strokeLineCap !== void 0) options.strokeLineCap = props.strokeLineCap;
2206
+ if (props.strokeLineJoin !== void 0) options.strokeLineJoin = props.strokeLineJoin;
2207
+ if (props.clickable !== void 0) options.clickable = props.clickable;
2208
+ if (props.visible !== void 0) options.visible = props.visible;
2209
+ if (props.zIndex !== void 0) options.zIndex = props.zIndex;
2210
+ if (props.startIcon !== void 0) options.startIcon = props.startIcon;
2211
+ if (props.startIconSize !== void 0) options.startIconSize = props.startIconSize;
2212
+ if (props.endIcon !== void 0) options.endIcon = props.endIcon;
2213
+ if (props.endIconSize !== void 0) options.endIconSize = props.endIconSize;
2214
+ return options;
2215
+ }
2216
+ function buildPolylineEventBindings(props) {
2217
+ return [
2218
+ {
2219
+ eventName: "click",
2220
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
2221
+ },
2222
+ {
2223
+ eventName: "dblclick",
2224
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
2225
+ },
2226
+ {
2227
+ eventName: "mousedown",
2228
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
2229
+ },
2230
+ {
2231
+ eventName: "mousemove",
2232
+ invoke: props.onMouseMove ? (event) => props.onMouseMove?.(event) : void 0
2233
+ },
2234
+ {
2235
+ eventName: "mouseout",
2236
+ invoke: props.onMouseOut ? (event) => props.onMouseOut?.(event) : void 0
2237
+ },
2238
+ {
2239
+ eventName: "mouseover",
2240
+ invoke: props.onMouseOver ? (event) => props.onMouseOver?.(event) : void 0
2241
+ },
2242
+ {
2243
+ eventName: "mouseup",
2244
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
2245
+ },
2246
+ {
2247
+ eventName: "rightclick",
2248
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
2249
+ },
2250
+ {
2251
+ eventName: "touchstart",
2252
+ invoke: props.onTouchStart ? (event) => props.onTouchStart?.(event) : void 0
2253
+ },
2254
+ {
2255
+ eventName: "touchmove",
2256
+ invoke: props.onTouchMove ? (event) => props.onTouchMove?.(event) : void 0
2257
+ },
2258
+ {
2259
+ eventName: "touchend",
2260
+ invoke: props.onTouchEnd ? (event) => props.onTouchEnd?.(event) : void 0
2261
+ },
2262
+ {
2263
+ eventName: "clickable_changed",
2264
+ invoke: props.onClickableChanged ? (event) => props.onClickableChanged?.(event) : void 0
2265
+ },
2266
+ {
2267
+ eventName: "endIcon_changed",
2268
+ invoke: props.onEndIconChanged ? (event) => props.onEndIconChanged?.(event) : void 0
2269
+ },
2270
+ {
2271
+ eventName: "endIconSize_changed",
2272
+ invoke: props.onEndIconSizeChanged ? (event) => props.onEndIconSizeChanged?.(event) : void 0
2273
+ },
2274
+ {
2275
+ eventName: "map_changed",
2276
+ invoke: props.onMapChanged ? (event) => props.onMapChanged?.(event) : void 0
2277
+ },
2278
+ {
2279
+ eventName: "path_changed",
2280
+ invoke: props.onPathChanged ? (event) => props.onPathChanged?.(event) : void 0
2281
+ },
2282
+ {
2283
+ eventName: "startIcon_changed",
2284
+ invoke: props.onStartIconChanged ? (event) => props.onStartIconChanged?.(event) : void 0
2285
+ },
2286
+ {
2287
+ eventName: "startIconSize_changed",
2288
+ invoke: props.onStartIconSizeChanged ? (event) => props.onStartIconSizeChanged?.(event) : void 0
2289
+ },
2290
+ {
2291
+ eventName: "strokeColor_changed",
2292
+ invoke: props.onStrokeColorChanged ? (event) => props.onStrokeColorChanged?.(event) : void 0
2293
+ },
2294
+ {
2295
+ eventName: "strokeLineCap_changed",
2296
+ invoke: props.onStrokeLineCapChanged ? (event) => props.onStrokeLineCapChanged?.(event) : void 0
2297
+ },
2298
+ {
2299
+ eventName: "strokeLineJoin_changed",
2300
+ invoke: props.onStrokeLineJoinChanged ? (event) => props.onStrokeLineJoinChanged?.(event) : void 0
2301
+ },
2302
+ {
2303
+ eventName: "strokeOpacity_changed",
2304
+ invoke: props.onStrokeOpacityChanged ? (event) => props.onStrokeOpacityChanged?.(event) : void 0
2305
+ },
2306
+ {
2307
+ eventName: "strokeStyle_changed",
2308
+ invoke: props.onStrokeStyleChanged ? (event) => props.onStrokeStyleChanged?.(event) : void 0
2309
+ },
2310
+ {
2311
+ eventName: "strokeWeight_changed",
2312
+ invoke: props.onStrokeWeightChanged ? (event) => props.onStrokeWeightChanged?.(event) : void 0
2313
+ },
2314
+ {
2315
+ eventName: "visible_changed",
2316
+ invoke: props.onVisibleChanged ? (event) => props.onVisibleChanged?.(event) : void 0
2317
+ },
2318
+ {
2319
+ eventName: "zIndex_changed",
2320
+ invoke: props.onZIndexChanged ? (event) => props.onZIndexChanged?.(event) : void 0
2321
+ }
2322
+ ];
2323
+ }
2324
+ const Polyline = forwardRef(function PolylineInner(props, ref) {
2325
+ const { map: contextMap, sdkStatus } = useNaverMap();
2326
+ const polylineRef = useRef(null);
2327
+ const polylineEventListenersRef = useRef([]);
2328
+ const onPolylineDestroyRef = useRef(props.onPolylineDestroy);
2329
+ const targetMap = props.map ?? contextMap;
2330
+ useEffect(() => {
2331
+ onPolylineDestroyRef.current = props.onPolylineDestroy;
2332
+ }, [props.onPolylineDestroy]);
2333
+ const invokePolylineMethod = useCallback((methodName, ...args) => {
2334
+ const polyline = polylineRef.current;
2335
+ if (!polyline) return;
2336
+ const method = polyline[methodName];
2337
+ if (typeof method !== "function") return;
2338
+ return method.apply(polyline, args);
2339
+ }, []);
2340
+ const teardownPolyline = useCallback(() => {
2341
+ const polyline = polylineRef.current;
2342
+ if (!polyline) return;
2343
+ try {
2344
+ removeOverlayEventListeners(polylineEventListenersRef.current);
2345
+ polylineEventListenersRef.current = [];
2346
+ naver.maps.Event.clearInstanceListeners(polyline);
2347
+ } catch (error) {
2348
+ console.error("[react-naver-maps-kit] failed to clear polyline listeners", error);
2349
+ }
2350
+ polyline.setMap(null);
2351
+ polylineRef.current = null;
2352
+ onPolylineDestroyRef.current?.();
2353
+ }, []);
2354
+ useImperativeHandle(ref, () => ({
2355
+ getInstance: () => polylineRef.current,
2356
+ getBounds: (...args) => invokePolylineMethod("getBounds", ...args),
2357
+ getClickable: (...args) => invokePolylineMethod("getClickable", ...args),
2358
+ getDistance: (...args) => invokePolylineMethod("getDistance", ...args),
2359
+ getDrawingRect: (...args) => invokePolylineMethod("getDrawingRect", ...args),
2360
+ getElement: (...args) => invokePolylineMethod("getElement", ...args),
2361
+ getMap: (...args) => invokePolylineMethod("getMap", ...args),
2362
+ getOptions: (...args) => invokePolylineMethod("getOptions", ...args),
2363
+ getPanes: (...args) => invokePolylineMethod("getPanes", ...args),
2364
+ getPath: (...args) => invokePolylineMethod("getPath", ...args),
2365
+ getProjection: (...args) => invokePolylineMethod("getProjection", ...args),
2366
+ getStyles: (...args) => invokePolylineMethod("getStyles", ...args),
2367
+ getVisible: (...args) => invokePolylineMethod("getVisible", ...args),
2368
+ getZIndex: (...args) => invokePolylineMethod("getZIndex", ...args),
2369
+ setClickable: (...args) => invokePolylineMethod("setClickable", ...args),
2370
+ setMap: (...args) => invokePolylineMethod("setMap", ...args),
2371
+ setOptions: (...args) => invokePolylineMethod("setOptions", ...args),
2372
+ setPath: (...args) => invokePolylineMethod("setPath", ...args),
2373
+ setStyles: (...args) => invokePolylineMethod("setStyles", ...args),
2374
+ setVisible: (...args) => invokePolylineMethod("setVisible", ...args),
2375
+ setZIndex: (...args) => invokePolylineMethod("setZIndex", ...args)
2376
+ }), [invokePolylineMethod]);
2377
+ useEffect(() => {
2378
+ if (sdkStatus !== "ready" || !targetMap || polylineRef.current) return;
2379
+ try {
2380
+ const polyline = new naver.maps.Polyline(toPolylineOptions(props, targetMap));
2381
+ polylineRef.current = polyline;
2382
+ bindOverlayEventListeners(polyline, polylineEventListenersRef, buildPolylineEventBindings(props));
2383
+ props.onPolylineReady?.(polyline);
2384
+ } catch (error) {
2385
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Polyline instance.");
2386
+ props.onPolylineError?.(normalizedError);
2387
+ }
2388
+ }, [
2389
+ props,
2390
+ sdkStatus,
2391
+ targetMap
2392
+ ]);
2393
+ useEffect(() => {
2394
+ const polyline = polylineRef.current;
2395
+ if (!polyline || !targetMap) return;
2396
+ polyline.setOptions(toPolylineOptions(props, targetMap));
2397
+ }, [props, targetMap]);
2398
+ useEffect(() => {
2399
+ const polyline = polylineRef.current;
2400
+ if (!polyline) return;
2401
+ bindOverlayEventListeners(polyline, polylineEventListenersRef, buildPolylineEventBindings(props));
2402
+ return () => {
2403
+ removeOverlayEventListeners(polylineEventListenersRef.current);
2404
+ polylineEventListenersRef.current = [];
2405
+ };
2406
+ }, [props]);
2407
+ useEffect(() => {
2408
+ return () => {
2409
+ teardownPolyline();
2410
+ };
2411
+ }, [teardownPolyline]);
2412
+ return null;
2413
+ });
2414
+ Polyline.displayName = "Polyline";
2415
+
2416
+ //#endregion
2417
+ //#region src/overlays/rectangle/Rectangle.tsx
2418
+ function toRectangleOptions(props, targetMap) {
2419
+ const options = { bounds: props.bounds };
2420
+ if (targetMap) options.map = targetMap;
2421
+ if (props.strokeWeight !== void 0) options.strokeWeight = props.strokeWeight;
2422
+ if (props.strokeOpacity !== void 0) options.strokeOpacity = props.strokeOpacity;
2423
+ if (props.strokeColor !== void 0) options.strokeColor = props.strokeColor;
2424
+ if (props.strokeStyle !== void 0) options.strokeStyle = props.strokeStyle;
2425
+ if (props.strokeLineCap !== void 0) options.strokeLineCap = props.strokeLineCap;
2426
+ if (props.strokeLineJoin !== void 0) options.strokeLineJoin = props.strokeLineJoin;
2427
+ if (props.fillColor !== void 0) options.fillColor = props.fillColor;
2428
+ if (props.fillOpacity !== void 0) options.fillOpacity = props.fillOpacity;
2429
+ if (props.clickable !== void 0) options.clickable = props.clickable;
2430
+ if (props.visible !== void 0) options.visible = props.visible;
2431
+ if (props.zIndex !== void 0) options.zIndex = props.zIndex;
2432
+ return options;
2433
+ }
2434
+ function buildRectangleEventBindings(props) {
2435
+ return [
2436
+ {
2437
+ eventName: "click",
2438
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
2439
+ },
2440
+ {
2441
+ eventName: "dblclick",
2442
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
2443
+ },
2444
+ {
2445
+ eventName: "mousedown",
2446
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
2447
+ },
2448
+ {
2449
+ eventName: "mousemove",
2450
+ invoke: props.onMouseMove ? (event) => props.onMouseMove?.(event) : void 0
2451
+ },
2452
+ {
2453
+ eventName: "mouseout",
2454
+ invoke: props.onMouseOut ? (event) => props.onMouseOut?.(event) : void 0
2455
+ },
2456
+ {
2457
+ eventName: "mouseover",
2458
+ invoke: props.onMouseOver ? (event) => props.onMouseOver?.(event) : void 0
2459
+ },
2460
+ {
2461
+ eventName: "mouseup",
2462
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
2463
+ },
2464
+ {
2465
+ eventName: "rightclick",
2466
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
2467
+ },
2468
+ {
2469
+ eventName: "touchstart",
2470
+ invoke: props.onTouchStart ? (event) => props.onTouchStart?.(event) : void 0
2471
+ },
2472
+ {
2473
+ eventName: "touchmove",
2474
+ invoke: props.onTouchMove ? (event) => props.onTouchMove?.(event) : void 0
2475
+ },
2476
+ {
2477
+ eventName: "touchend",
2478
+ invoke: props.onTouchEnd ? (event) => props.onTouchEnd?.(event) : void 0
2479
+ },
2480
+ {
2481
+ eventName: "bounds_changed",
2482
+ invoke: props.onBoundsChanged ? (event) => props.onBoundsChanged?.(event) : void 0
2483
+ },
2484
+ {
2485
+ eventName: "clickable_changed",
2486
+ invoke: props.onClickableChanged ? (event) => props.onClickableChanged?.(event) : void 0
2487
+ },
2488
+ {
2489
+ eventName: "fillColor_changed",
2490
+ invoke: props.onFillColorChanged ? (event) => props.onFillColorChanged?.(event) : void 0
2491
+ },
2492
+ {
2493
+ eventName: "fillOpacity_changed",
2494
+ invoke: props.onFillOpacityChanged ? (event) => props.onFillOpacityChanged?.(event) : void 0
2495
+ },
2496
+ {
2497
+ eventName: "map_changed",
2498
+ invoke: props.onMapChanged ? (event) => props.onMapChanged?.(event) : void 0
2499
+ },
2500
+ {
2501
+ eventName: "strokeColor_changed",
2502
+ invoke: props.onStrokeColorChanged ? (event) => props.onStrokeColorChanged?.(event) : void 0
2503
+ },
2504
+ {
2505
+ eventName: "strokeLineCap_changed",
2506
+ invoke: props.onStrokeLineCapChanged ? (event) => props.onStrokeLineCapChanged?.(event) : void 0
2507
+ },
2508
+ {
2509
+ eventName: "strokeLineJoin_changed",
2510
+ invoke: props.onStrokeLineJoinChanged ? (event) => props.onStrokeLineJoinChanged?.(event) : void 0
2511
+ },
2512
+ {
2513
+ eventName: "strokeOpacity_changed",
2514
+ invoke: props.onStrokeOpacityChanged ? (event) => props.onStrokeOpacityChanged?.(event) : void 0
2515
+ },
2516
+ {
2517
+ eventName: "strokeStyle_changed",
2518
+ invoke: props.onStrokeStyleChanged ? (event) => props.onStrokeStyleChanged?.(event) : void 0
2519
+ },
2520
+ {
2521
+ eventName: "strokeWeight_changed",
2522
+ invoke: props.onStrokeWeightChanged ? (event) => props.onStrokeWeightChanged?.(event) : void 0
2523
+ },
2524
+ {
2525
+ eventName: "visible_changed",
2526
+ invoke: props.onVisibleChanged ? (event) => props.onVisibleChanged?.(event) : void 0
2527
+ },
2528
+ {
2529
+ eventName: "zIndex_changed",
2530
+ invoke: props.onZIndexChanged ? (event) => props.onZIndexChanged?.(event) : void 0
2531
+ }
2532
+ ];
2533
+ }
2534
+ const Rectangle = forwardRef(function RectangleInner(props, ref) {
2535
+ const { map: contextMap, sdkStatus } = useNaverMap();
2536
+ const rectangleRef = useRef(null);
2537
+ const rectangleEventListenersRef = useRef([]);
2538
+ const onRectangleDestroyRef = useRef(props.onRectangleDestroy);
2539
+ const targetMap = props.map ?? contextMap;
2540
+ useEffect(() => {
2541
+ onRectangleDestroyRef.current = props.onRectangleDestroy;
2542
+ }, [props.onRectangleDestroy]);
2543
+ const invokeRectangleMethod = useCallback((methodName, ...args) => {
2544
+ const rectangle = rectangleRef.current;
2545
+ if (!rectangle) return;
2546
+ const method = rectangle[methodName];
2547
+ if (typeof method !== "function") return;
2548
+ return method.apply(rectangle, args);
2549
+ }, []);
2550
+ const teardownRectangle = useCallback(() => {
2551
+ const rectangle = rectangleRef.current;
2552
+ if (!rectangle) return;
2553
+ try {
2554
+ removeOverlayEventListeners(rectangleEventListenersRef.current);
2555
+ rectangleEventListenersRef.current = [];
2556
+ naver.maps.Event.clearInstanceListeners(rectangle);
2557
+ } catch (error) {
2558
+ console.error("[react-naver-maps-kit] failed to clear rectangle listeners", error);
2559
+ }
2560
+ rectangle.setMap(null);
2561
+ rectangleRef.current = null;
2562
+ onRectangleDestroyRef.current?.();
2563
+ }, []);
2564
+ useImperativeHandle(ref, () => ({
2565
+ getInstance: () => rectangleRef.current,
2566
+ getAreaSize: (...args) => invokeRectangleMethod("getAreaSize", ...args),
2567
+ getBounds: (...args) => invokeRectangleMethod("getBounds", ...args),
2568
+ getClickable: (...args) => invokeRectangleMethod("getClickable", ...args),
2569
+ getDrawingRect: (...args) => invokeRectangleMethod("getDrawingRect", ...args),
2570
+ getElement: (...args) => invokeRectangleMethod("getElement", ...args),
2571
+ getMap: (...args) => invokeRectangleMethod("getMap", ...args),
2572
+ getOptions: (...args) => invokeRectangleMethod("getOptions", ...args),
2573
+ getPanes: (...args) => invokeRectangleMethod("getPanes", ...args),
2574
+ getProjection: (...args) => invokeRectangleMethod("getProjection", ...args),
2575
+ getStyles: (...args) => invokeRectangleMethod("getStyles", ...args),
2576
+ getVisible: (...args) => invokeRectangleMethod("getVisible", ...args),
2577
+ getZIndex: (...args) => invokeRectangleMethod("getZIndex", ...args),
2578
+ setBounds: (...args) => invokeRectangleMethod("setBounds", ...args),
2579
+ setClickable: (...args) => invokeRectangleMethod("setClickable", ...args),
2580
+ setMap: (...args) => invokeRectangleMethod("setMap", ...args),
2581
+ setOptions: (...args) => invokeRectangleMethod("setOptions", ...args),
2582
+ setStyles: (...args) => invokeRectangleMethod("setStyles", ...args),
2583
+ setVisible: (...args) => invokeRectangleMethod("setVisible", ...args),
2584
+ setZIndex: (...args) => invokeRectangleMethod("setZIndex", ...args)
2585
+ }), [invokeRectangleMethod]);
2586
+ useEffect(() => {
2587
+ if (sdkStatus !== "ready" || !targetMap || rectangleRef.current) return;
2588
+ try {
2589
+ const rectangle = new naver.maps.Rectangle(toRectangleOptions(props, targetMap));
2590
+ rectangleRef.current = rectangle;
2591
+ bindOverlayEventListeners(rectangle, rectangleEventListenersRef, buildRectangleEventBindings(props));
2592
+ props.onRectangleReady?.(rectangle);
2593
+ } catch (error) {
2594
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Rectangle instance.");
2595
+ props.onRectangleError?.(normalizedError);
2596
+ }
2597
+ }, [
2598
+ props,
2599
+ sdkStatus,
2600
+ targetMap
2601
+ ]);
2602
+ useEffect(() => {
2603
+ const rectangle = rectangleRef.current;
2604
+ if (!rectangle || !targetMap) return;
2605
+ rectangle.setOptions(toRectangleOptions(props, targetMap));
2606
+ }, [props, targetMap]);
2607
+ useEffect(() => {
2608
+ const rectangle = rectangleRef.current;
2609
+ if (!rectangle) return;
2610
+ bindOverlayEventListeners(rectangle, rectangleEventListenersRef, buildRectangleEventBindings(props));
2611
+ return () => {
2612
+ removeOverlayEventListeners(rectangleEventListenersRef.current);
2613
+ rectangleEventListenersRef.current = [];
2614
+ };
2615
+ }, [props]);
2616
+ useEffect(() => {
2617
+ return () => {
2618
+ teardownRectangle();
2619
+ };
2620
+ }, [teardownRectangle]);
2621
+ return null;
2622
+ });
2623
+ Rectangle.displayName = "Rectangle";
2624
+
2625
+ //#endregion
2626
+ //#region src/index.ts
2627
+ const version = "0.0.1";
2628
+
2629
+ //#endregion
2630
+ export { Circle, Ellipse, GroundOverlay, InfoWindow, Marker, NaverMap, NaverMapContext, NaverMapProvider, Polygon, Polyline, Rectangle, loadNaverMapsScript, useNaverMap, useNaverMapInstance, version };
2631
+ //# sourceMappingURL=index.js.map