react-naver-maps-kit 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  let react = require("react");
3
3
  let react_jsx_runtime = require("react/jsx-runtime");
4
4
  let react_dom = require("react-dom");
5
- let react_dom_client = require("react-dom/client");
5
+ let module$1 = require("module");
6
6
 
7
7
  //#region src/core/loader/loadNaverMapsScript.ts
8
8
  const NAVER_MAPS_SCRIPT_BASE_URL = "https://oapi.map.naver.com/openapi/v3/maps.js";
@@ -876,15 +876,23 @@ function useNaverMapInstance(options = {}) {
876
876
  //#endregion
877
877
  //#region src/overlays/marker-clusterer/ClustererContext.ts
878
878
  /**
879
- * `<MarkerClusterer>`가 제공하는 React Context.
879
+ * `<MarkerClusterer>`가 제공하는 registry Context.
880
+ * register/unregister/enabled만 포함하며, enabled가 바뀔 때만 갱신됩니다.
880
881
  *
881
- * `<Marker>`는 이 context를 통해 클러스터러에 자신을 등록합니다.
882
- * `null`이면 클러스터러 밖에 있는 것이므로 일반 마커로 동작합니다.
883
- *
884
- * @internal 라이브러리 내부 전용. 직접 사용하지 마세요.
882
+ * @internal
885
883
  */
886
884
  const ClustererContext = (0, react.createContext)(null);
887
885
  ClustererContext.displayName = "ClustererContext";
886
+ /**
887
+ * `<MarkerClusterer>`가 제공하는 visibility Context.
888
+ * 재계산 시마다 갱신되며, 클러스터링 안 된 마커 ID 집합을 담습니다.
889
+ *
890
+ * `<Marker>`는 이 context를 읽어 자신이 보여야 할지 판단합니다.
891
+ *
892
+ * @internal
893
+ */
894
+ const ClustererVisibilityContext = (0, react.createContext)(/* @__PURE__ */ new Set());
895
+ ClustererVisibilityContext.displayName = "ClustererVisibilityContext";
888
896
 
889
897
  //#endregion
890
898
  //#region src/overlays/marker/Marker.tsx
@@ -1036,11 +1044,15 @@ function toLatLngLiteral(position) {
1036
1044
  const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1037
1045
  const { map: contextMap, sdkStatus } = useNaverMap();
1038
1046
  const clustererRegistry = (0, react.useContext)(ClustererContext);
1047
+ const visibleIds = (0, react.useContext)(ClustererVisibilityContext);
1039
1048
  const isInsideClusterer = clustererRegistry !== null && clustererRegistry.enabled;
1049
+ const autoId = (0, react.useId)();
1050
+ const effectiveId = props.clustererItemId ?? autoId;
1051
+ const isHiddenByClusterer = isInsideClusterer && !visibleIds.has(effectiveId);
1040
1052
  const markerRef = (0, react.useRef)(null);
1041
1053
  const markerEventListenersRef = (0, react.useRef)([]);
1042
1054
  const onMarkerDestroyRef = (0, react.useRef)(props.onMarkerDestroy);
1043
- const [markerDiv, setMarkerDiv] = (0, react.useState)(null);
1055
+ const [markerDiv] = (0, react.useState)(() => document.createElement("div"));
1044
1056
  const [portalReady, setPortalReady] = (0, react.useState)(false);
1045
1057
  const hasChildren = props.children !== void 0 && props.children !== null;
1046
1058
  const targetMap = props.map ?? contextMap;
@@ -1050,8 +1062,7 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1050
1062
  });
1051
1063
  (0, react.useEffect)(() => {
1052
1064
  if (!clustererRegistry) return;
1053
- const id = props.clustererItemId;
1054
- if (id === void 0 || id === null) return;
1065
+ const id = props.clustererItemId ?? autoId;
1055
1066
  const latLng = toLatLngLiteral(props.position);
1056
1067
  if (!latLng) return;
1057
1068
  clustererRegistry.register({
@@ -1064,6 +1075,7 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1064
1075
  clustererRegistry.unregister(id);
1065
1076
  };
1066
1077
  }, [
1078
+ autoId,
1067
1079
  clustererRegistry,
1068
1080
  props.clustererItemId,
1069
1081
  props.position,
@@ -1071,17 +1083,10 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1071
1083
  props.icon
1072
1084
  ]);
1073
1085
  (0, react.useEffect)(() => {
1074
- if (isInsideClusterer) return;
1075
1086
  onMarkerDestroyRef.current = props.onMarkerDestroy;
1076
- }, [isInsideClusterer, props.onMarkerDestroy]);
1087
+ }, [props.onMarkerDestroy]);
1077
1088
  (0, react.useEffect)(() => {
1078
- if (isInsideClusterer) return;
1079
- if (typeof document === "undefined") return;
1080
- setMarkerDiv(document.createElement("div"));
1081
- }, [isInsideClusterer]);
1082
- (0, react.useEffect)(() => {
1083
- if (isInsideClusterer) return;
1084
- if (!hasChildren || !markerDiv) {
1089
+ if (!hasChildren) {
1085
1090
  setPortalReady(false);
1086
1091
  return;
1087
1092
  }
@@ -1097,11 +1102,7 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1097
1102
  return () => {
1098
1103
  observer.disconnect();
1099
1104
  };
1100
- }, [
1101
- isInsideClusterer,
1102
- hasChildren,
1103
- markerDiv
1104
- ]);
1105
+ }, [hasChildren, markerDiv]);
1105
1106
  const invokeMarkerMethod = (0, react.useCallback)((methodName, ...args) => {
1106
1107
  const marker = markerRef.current;
1107
1108
  if (!marker) return;
@@ -1157,7 +1158,7 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1157
1158
  setZIndex: (...args) => invokeMarkerMethod("setZIndex", ...args)
1158
1159
  }), [invokeMarkerMethod]);
1159
1160
  (0, react.useEffect)(() => {
1160
- if (isInsideClusterer) return;
1161
+ if (isHiddenByClusterer) return;
1161
1162
  if (sdkStatus !== "ready" || !targetMap || markerRef.current) return;
1162
1163
  if (hasChildren && !portalReady) return;
1163
1164
  try {
@@ -1173,7 +1174,7 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1173
1174
  propsRef.current.onMarkerError?.(normalizedError);
1174
1175
  }
1175
1176
  }, [
1176
- isInsideClusterer,
1177
+ isHiddenByClusterer,
1177
1178
  hasChildren,
1178
1179
  markerDiv,
1179
1180
  portalReady,
@@ -1181,7 +1182,7 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1181
1182
  targetMap
1182
1183
  ]);
1183
1184
  (0, react.useLayoutEffect)(() => {
1184
- if (isInsideClusterer) return;
1185
+ if (isHiddenByClusterer) return;
1185
1186
  const marker = markerRef.current;
1186
1187
  if (!marker || !targetMap) return;
1187
1188
  const rafId = requestAnimationFrame(() => {
@@ -1195,7 +1196,7 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1195
1196
  cancelAnimationFrame(rafId);
1196
1197
  };
1197
1198
  }, [
1198
- isInsideClusterer,
1199
+ isHiddenByClusterer,
1199
1200
  hasChildren,
1200
1201
  markerDiv,
1201
1202
  portalReady,
@@ -1214,7 +1215,7 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1214
1215
  props.collisionBoxSize
1215
1216
  ]);
1216
1217
  (0, react.useEffect)(() => {
1217
- if (isInsideClusterer) return;
1218
+ if (isHiddenByClusterer) return;
1218
1219
  const marker = markerRef.current;
1219
1220
  if (!marker) return;
1220
1221
  bindMarkerEventListeners(marker, markerEventListenersRef, buildMarkerEventBindings(propsRef));
@@ -1224,14 +1225,14 @@ const Marker = (0, react.forwardRef)(function MarkerInner(props, ref) {
1224
1225
  markerEventListenersRef.current = [];
1225
1226
  }
1226
1227
  };
1227
- }, [isInsideClusterer]);
1228
+ }, [isHiddenByClusterer]);
1228
1229
  (0, react.useEffect)(() => {
1229
- if (isInsideClusterer) return;
1230
+ if (isHiddenByClusterer) return;
1230
1231
  return () => {
1231
1232
  teardownMarker();
1232
1233
  };
1233
- }, [isInsideClusterer, teardownMarker]);
1234
- if (isInsideClusterer) return null;
1234
+ }, [isHiddenByClusterer, teardownMarker]);
1235
+ if (isHiddenByClusterer) return null;
1235
1236
  if (!hasChildren || !markerDiv) return null;
1236
1237
  return (0, react_dom.createPortal)(props.children, markerDiv);
1237
1238
  });
@@ -2225,7 +2226,8 @@ function padBounds(bounds, padding) {
2225
2226
  * 내부 registry에 위치·데이터를 등록합니다.
2226
2227
  * 2. `MarkerClusterer`는 지도 이벤트(`idle`, `move`, `zoom`) 발생 시
2227
2228
  * 현재 줌·뷰포트 기준으로 클러스터를 재계산합니다.
2228
- * 3. 클러스터 마커는 `createRoot`를 이용해 React 컴포넌트를 HTML 아이콘으로 렌더링합니다.
2229
+ * 3. 클러스터 마커는 `<Marker>` JSX로 렌더링되며, children으로 클러스터 아이콘이 전달됩니다.
2230
+ * 4. 클러스터에 포함되지 않은 단독 포인트는 원래 `<Marker>` children을 그대로 표시합니다.
2229
2231
  *
2230
2232
  * ## 기본 사용법
2231
2233
  *
@@ -2241,10 +2243,11 @@ function padBounds(bounds, padding) {
2241
2243
  * {points.map(p => (
2242
2244
  * <Marker
2243
2245
  * key={p.id}
2244
- * clustererItemId={p.id}
2245
2246
  * position={p.position}
2246
2247
  * item={p}
2247
- * />
2248
+ * >
2249
+ * <CustomPin />
2250
+ * </Marker>
2248
2251
  * ))}
2249
2252
  * </MarkerClusterer>
2250
2253
  * </NaverMap>
@@ -2252,7 +2255,6 @@ function padBounds(bounds, padding) {
2252
2255
  *
2253
2256
  * ## 주의 사항
2254
2257
  *
2255
- * - `<Marker>`에 반드시 `clustererItemId` prop을 지정해야 합니다.
2256
2258
  * - `<MarkerClusterer>`는 반드시 `<NaverMap>` 내부에 위치해야 합니다.
2257
2259
  * - `enabled={false}`로 설정하면 클러스터링이 해제되고 각 `<Marker>`가 개별 마커로 렌더링됩니다.
2258
2260
  *
@@ -2291,10 +2293,8 @@ function MarkerClusterer(props) {
2291
2293
  if (prev && prev !== algorithm) prev.destroy?.();
2292
2294
  };
2293
2295
  }, [algorithm]);
2294
- const pointMarkersRef = (0, react.useRef)(/* @__PURE__ */ new Map());
2295
- const clusterMarkersRef = (0, react.useRef)(/* @__PURE__ */ new Map());
2296
- const clusterIconRootsRef = (0, react.useRef)(/* @__PURE__ */ new Map());
2297
- const clusterIconContainersRef = (0, react.useRef)(/* @__PURE__ */ new Map());
2296
+ const [clusters, setClusters] = (0, react.useState)([]);
2297
+ const [visibleIds, setVisibleIds] = (0, react.useState)(/* @__PURE__ */ new Set());
2298
2298
  const helpersRef = (0, react.useRef)({
2299
2299
  zoomToCluster: () => {},
2300
2300
  fitBounds: () => {}
@@ -2327,94 +2327,22 @@ function MarkerClusterer(props) {
2327
2327
  (0, react.useEffect)(() => {
2328
2328
  onClusterClickRef.current = onClusterClick;
2329
2329
  }, [onClusterClick]);
2330
- const clusterIconRef = (0, react.useRef)(clusterIcon);
2331
- (0, react.useEffect)(() => {
2332
- clusterIconRef.current = clusterIcon;
2333
- }, [clusterIcon]);
2334
2330
  const recompute = (0, react.useCallback)(() => {
2335
2331
  if (!map || sdkStatus !== "ready" || !enabled) return;
2336
2332
  const zoom = map.getZoom();
2337
2333
  const bounds = getMapBounds(map);
2338
2334
  const items = Array.from(registryRef.current.values());
2339
- const { clusters, points } = algorithm.cluster(items, {
2335
+ const { clusters: rawClusters, points } = algorithm.cluster(items, {
2340
2336
  zoom,
2341
2337
  bounds
2342
2338
  });
2343
2339
  const maxItems = clusterData?.maxItemsInCluster;
2344
2340
  const includeItems = clusterData?.includeItems ?? true;
2345
- const processedClusters = clusters.map((c) => ({
2341
+ setClusters(rawClusters.map((c) => ({
2346
2342
  ...c,
2347
2343
  items: includeItems ? maxItems !== void 0 ? c.items?.slice(0, maxItems) : c.items : void 0
2348
- }));
2349
- const nextPointIds = new Set(points.map((p) => p.id));
2350
- const prevPointMarkers = pointMarkersRef.current;
2351
- for (const [id, marker] of prevPointMarkers) if (!nextPointIds.has(id)) {
2352
- marker.setMap(null);
2353
- prevPointMarkers.delete(id);
2354
- }
2355
- for (const point of points) {
2356
- const existing = prevPointMarkers.get(point.id);
2357
- if (existing) {
2358
- const pos = new naver.maps.LatLng(point.position.lat, point.position.lng);
2359
- existing.setPosition(pos);
2360
- if (point.markerOptions) existing.setOptions({ ...point.markerOptions });
2361
- } else {
2362
- const opts = {
2363
- position: new naver.maps.LatLng(point.position.lat, point.position.lng),
2364
- map
2365
- };
2366
- if (point.markerOptions) Object.assign(opts, point.markerOptions);
2367
- const marker = new naver.maps.Marker(opts);
2368
- prevPointMarkers.set(point.id, marker);
2369
- }
2370
- }
2371
- const nextClusterIds = new Set(processedClusters.map((c) => c.id));
2372
- const prevClusterMarkers = clusterMarkersRef.current;
2373
- const prevRoots = clusterIconRootsRef.current;
2374
- const prevContainers = clusterIconContainersRef.current;
2375
- for (const [id, marker] of prevClusterMarkers) if (!nextClusterIds.has(id)) {
2376
- marker.setMap(null);
2377
- prevClusterMarkers.delete(id);
2378
- const root = prevRoots.get(id);
2379
- if (root) {
2380
- root.unmount();
2381
- prevRoots.delete(id);
2382
- }
2383
- prevContainers.delete(id);
2384
- }
2385
- for (const cluster of processedClusters) {
2386
- const existingMarker = prevClusterMarkers.get(cluster.id);
2387
- const renderer = clusterIconRef.current;
2388
- const iconNode = renderer ? renderer({
2389
- cluster,
2390
- count: cluster.count
2391
- }) : DefaultClusterIcon({ count: cluster.count });
2392
- if (existingMarker) {
2393
- existingMarker.setPosition(new naver.maps.LatLng(cluster.position.lat, cluster.position.lng));
2394
- const root = prevRoots.get(cluster.id);
2395
- if (root) root.render(iconNode);
2396
- } else {
2397
- const container = document.createElement("div");
2398
- container.style.cursor = "pointer";
2399
- const root = (0, react_dom_client.createRoot)(container);
2400
- root.render(iconNode);
2401
- prevContainers.set(cluster.id, container);
2402
- prevRoots.set(cluster.id, root);
2403
- const marker = new naver.maps.Marker({
2404
- position: new naver.maps.LatLng(cluster.position.lat, cluster.position.lng),
2405
- map,
2406
- icon: { content: container },
2407
- clickable: true
2408
- });
2409
- naver.maps.Event.addListener(marker, "click", () => {
2410
- onClusterClickRef.current?.({
2411
- cluster,
2412
- helpers: helpersRef.current
2413
- });
2414
- });
2415
- prevClusterMarkers.set(cluster.id, marker);
2416
- }
2417
- }
2344
+ })));
2345
+ setVisibleIds(new Set(points.map((p) => p.id)));
2418
2346
  }, [
2419
2347
  map,
2420
2348
  sdkStatus,
@@ -2455,31 +2383,31 @@ function MarkerClusterer(props) {
2455
2383
  behavior?.debounceMs,
2456
2384
  recompute
2457
2385
  ]);
2458
- (0, react.useEffect)(() => {
2459
- return () => {
2460
- for (const marker of pointMarkersRef.current.values()) marker.setMap(null);
2461
- pointMarkersRef.current.clear();
2462
- for (const marker of clusterMarkersRef.current.values()) marker.setMap(null);
2463
- clusterMarkersRef.current.clear();
2464
- for (const root of clusterIconRootsRef.current.values()) root.unmount();
2465
- clusterIconRootsRef.current.clear();
2466
- clusterIconContainersRef.current.clear();
2467
- };
2468
- }, []);
2469
2386
  (0, react.useEffect)(() => {
2470
2387
  if (enabled) return;
2471
- for (const marker of pointMarkersRef.current.values()) marker.setMap(null);
2472
- pointMarkersRef.current.clear();
2473
- for (const marker of clusterMarkersRef.current.values()) marker.setMap(null);
2474
- clusterMarkersRef.current.clear();
2475
- for (const root of clusterIconRootsRef.current.values()) root.unmount();
2476
- clusterIconRootsRef.current.clear();
2477
- clusterIconContainersRef.current.clear();
2388
+ setClusters([]);
2389
+ setVisibleIds(/* @__PURE__ */ new Set());
2478
2390
  }, [enabled]);
2479
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClustererContext.Provider, {
2391
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClustererContext.Provider, {
2480
2392
  value: registry,
2481
- children
2482
- });
2393
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClustererVisibilityContext.Provider, {
2394
+ value: visibleIds,
2395
+ children
2396
+ })
2397
+ }), enabled && clusters.map((cluster) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Marker, {
2398
+ position: cluster.position,
2399
+ clickable: true,
2400
+ onClick: () => {
2401
+ onClusterClickRef.current?.({
2402
+ cluster,
2403
+ helpers: helpersRef.current
2404
+ });
2405
+ },
2406
+ children: clusterIcon ? clusterIcon({
2407
+ cluster,
2408
+ count: cluster.count
2409
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultClusterIcon, { count: cluster.count })
2410
+ }, cluster.id))] });
2483
2411
  }
2484
2412
  MarkerClusterer.displayName = "MarkerClusterer";
2485
2413
 
@@ -3960,16 +3888,928 @@ const Rectangle = (0, react.forwardRef)(function RectangleInner(props, ref) {
3960
3888
  });
3961
3889
  Rectangle.displayName = "Rectangle";
3962
3890
 
3891
+ //#endregion
3892
+ //#region src/overlays/data/GeoJson.tsx
3893
+ function buildGeoJsonEventBindings(props) {
3894
+ return [
3895
+ {
3896
+ eventName: "addfeature",
3897
+ invoke: props.onAddFeature ? (event) => props.onAddFeature?.(event) : void 0
3898
+ },
3899
+ {
3900
+ eventName: "removefeature",
3901
+ invoke: props.onRemoveFeature ? (event) => props.onRemoveFeature?.(event) : void 0
3902
+ },
3903
+ {
3904
+ eventName: "property_changed",
3905
+ invoke: props.onPropertyChanged ? (event) => props.onPropertyChanged?.(event) : void 0
3906
+ },
3907
+ {
3908
+ eventName: "click",
3909
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
3910
+ },
3911
+ {
3912
+ eventName: "dblclick",
3913
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
3914
+ },
3915
+ {
3916
+ eventName: "rightclick",
3917
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
3918
+ },
3919
+ {
3920
+ eventName: "mousedown",
3921
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
3922
+ },
3923
+ {
3924
+ eventName: "mouseup",
3925
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
3926
+ },
3927
+ {
3928
+ eventName: "mouseover",
3929
+ invoke: props.onMouseOver ? (event) => props.onMouseOver?.(event) : void 0
3930
+ },
3931
+ {
3932
+ eventName: "mouseout",
3933
+ invoke: props.onMouseOut ? (event) => props.onMouseOut?.(event) : void 0
3934
+ }
3935
+ ];
3936
+ }
3937
+ const GeoJson = (0, react.forwardRef)(function GeoJsonInner(props, ref) {
3938
+ const { map: contextMap, sdkStatus } = useNaverMap();
3939
+ const dataRef = (0, react.useRef)(null);
3940
+ const dataEventListenersRef = (0, react.useRef)([]);
3941
+ const onDataDestroyRef = (0, react.useRef)(props.onDataDestroy);
3942
+ const prevDataRef = (0, react.useRef)(null);
3943
+ (0, react.useEffect)(() => {
3944
+ onDataDestroyRef.current = props.onDataDestroy;
3945
+ }, [props.onDataDestroy]);
3946
+ const invokeDataMethod = (0, react.useCallback)((methodName, ...args) => {
3947
+ const data = dataRef.current;
3948
+ if (!data) return;
3949
+ const method = data[methodName];
3950
+ if (typeof method !== "function") return;
3951
+ return method.apply(data, args);
3952
+ }, []);
3953
+ const teardownData = (0, react.useCallback)(() => {
3954
+ const data = dataRef.current;
3955
+ if (!data) return;
3956
+ try {
3957
+ removeOverlayEventListeners(dataEventListenersRef.current);
3958
+ dataEventListenersRef.current = [];
3959
+ naver.maps.Event.clearInstanceListeners(data);
3960
+ } catch (error) {
3961
+ console.error("[react-naver-maps-kit] failed to clear GeoJson data layer listeners", error);
3962
+ }
3963
+ data.setMap(null);
3964
+ dataRef.current = null;
3965
+ prevDataRef.current = null;
3966
+ onDataDestroyRef.current?.();
3967
+ }, []);
3968
+ (0, react.useImperativeHandle)(ref, () => ({
3969
+ getInstance: () => dataRef.current,
3970
+ getAllFeature: (...args) => invokeDataMethod("getAllFeature", ...args),
3971
+ getFeatureById: (...args) => invokeDataMethod("getFeatureById", ...args),
3972
+ getMap: (...args) => invokeDataMethod("getMap", ...args),
3973
+ getStyle: (...args) => invokeDataMethod("getStyle", ...args),
3974
+ overrideStyle: (...args) => invokeDataMethod("overrideStyle", ...args),
3975
+ removeFeature: (...args) => invokeDataMethod("removeFeature", ...args),
3976
+ revertStyle: (...args) => invokeDataMethod("revertStyle", ...args),
3977
+ setStyle: (...args) => invokeDataMethod("setStyle", ...args),
3978
+ toGeoJson: (...args) => invokeDataMethod("toGeoJson", ...args)
3979
+ }), [invokeDataMethod]);
3980
+ (0, react.useEffect)(() => {
3981
+ if (sdkStatus !== "ready" || !contextMap || dataRef.current) return;
3982
+ try {
3983
+ const data = new naver.maps.Data();
3984
+ data.setMap(contextMap);
3985
+ if (props.style) data.setStyle(props.style);
3986
+ const features = data.addGeoJson(props.data, props.autoStyle ?? true);
3987
+ prevDataRef.current = props.data;
3988
+ dataRef.current = data;
3989
+ bindOverlayEventListeners(data, dataEventListenersRef, buildGeoJsonEventBindings(props));
3990
+ props.onDataReady?.(data);
3991
+ props.onFeaturesAdded?.(features);
3992
+ } catch (error) {
3993
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Data instance for GeoJson.");
3994
+ props.onDataError?.(normalizedError);
3995
+ }
3996
+ }, [sdkStatus, contextMap]);
3997
+ (0, react.useEffect)(() => {
3998
+ const data = dataRef.current;
3999
+ if (!data || props.data === prevDataRef.current) return;
4000
+ try {
4001
+ if (prevDataRef.current) data.removeGeoJson(prevDataRef.current);
4002
+ const features = data.addGeoJson(props.data, props.autoStyle ?? true);
4003
+ prevDataRef.current = props.data;
4004
+ props.onFeaturesAdded?.(features);
4005
+ } catch (error) {
4006
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to update GeoJson data.");
4007
+ props.onDataError?.(normalizedError);
4008
+ }
4009
+ }, [props.data, props.autoStyle]);
4010
+ (0, react.useEffect)(() => {
4011
+ const data = dataRef.current;
4012
+ if (!data) return;
4013
+ if (props.style) data.setStyle(props.style);
4014
+ }, [props.style]);
4015
+ (0, react.useEffect)(() => {
4016
+ const data = dataRef.current;
4017
+ if (!data) return;
4018
+ bindOverlayEventListeners(data, dataEventListenersRef, buildGeoJsonEventBindings(props));
4019
+ return () => {
4020
+ removeOverlayEventListeners(dataEventListenersRef.current);
4021
+ dataEventListenersRef.current = [];
4022
+ };
4023
+ }, [props]);
4024
+ (0, react.useEffect)(() => {
4025
+ return () => {
4026
+ teardownData();
4027
+ };
4028
+ }, [teardownData]);
4029
+ return null;
4030
+ });
4031
+ GeoJson.displayName = "GeoJson";
4032
+
4033
+ //#endregion
4034
+ //#region src/overlays/data/Gpx.tsx
4035
+ function buildGpxEventBindings(props) {
4036
+ return [
4037
+ {
4038
+ eventName: "addfeature",
4039
+ invoke: props.onAddFeature ? (event) => props.onAddFeature?.(event) : void 0
4040
+ },
4041
+ {
4042
+ eventName: "removefeature",
4043
+ invoke: props.onRemoveFeature ? (event) => props.onRemoveFeature?.(event) : void 0
4044
+ },
4045
+ {
4046
+ eventName: "property_changed",
4047
+ invoke: props.onPropertyChanged ? (event) => props.onPropertyChanged?.(event) : void 0
4048
+ },
4049
+ {
4050
+ eventName: "click",
4051
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
4052
+ },
4053
+ {
4054
+ eventName: "dblclick",
4055
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
4056
+ },
4057
+ {
4058
+ eventName: "rightclick",
4059
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
4060
+ },
4061
+ {
4062
+ eventName: "mousedown",
4063
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
4064
+ },
4065
+ {
4066
+ eventName: "mouseup",
4067
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
4068
+ },
4069
+ {
4070
+ eventName: "mouseover",
4071
+ invoke: props.onMouseOver ? (event) => props.onMouseOver?.(event) : void 0
4072
+ },
4073
+ {
4074
+ eventName: "mouseout",
4075
+ invoke: props.onMouseOut ? (event) => props.onMouseOut?.(event) : void 0
4076
+ }
4077
+ ];
4078
+ }
4079
+ function parseXml(xmlString) {
4080
+ const doc = new DOMParser().parseFromString(xmlString, "application/xml");
4081
+ const parseError = doc.querySelector("parsererror");
4082
+ if (parseError) throw new Error(`XML parse error: ${parseError.textContent}`);
4083
+ return doc;
4084
+ }
4085
+ const Gpx = (0, react.forwardRef)(function GpxInner(props, ref) {
4086
+ const { map: contextMap, sdkStatus } = useNaverMap();
4087
+ const dataRef = (0, react.useRef)(null);
4088
+ const dataEventListenersRef = (0, react.useRef)([]);
4089
+ const onDataDestroyRef = (0, react.useRef)(props.onDataDestroy);
4090
+ const prevUrlRef = (0, react.useRef)(null);
4091
+ const abortRef = (0, react.useRef)(null);
4092
+ (0, react.useEffect)(() => {
4093
+ onDataDestroyRef.current = props.onDataDestroy;
4094
+ }, [props.onDataDestroy]);
4095
+ const invokeDataMethod = (0, react.useCallback)((methodName, ...args) => {
4096
+ const data = dataRef.current;
4097
+ if (!data) return;
4098
+ const method = data[methodName];
4099
+ if (typeof method !== "function") return;
4100
+ return method.apply(data, args);
4101
+ }, []);
4102
+ const teardownData = (0, react.useCallback)(() => {
4103
+ abortRef.current?.abort();
4104
+ abortRef.current = null;
4105
+ const data = dataRef.current;
4106
+ if (!data) return;
4107
+ try {
4108
+ removeOverlayEventListeners(dataEventListenersRef.current);
4109
+ dataEventListenersRef.current = [];
4110
+ naver.maps.Event.clearInstanceListeners(data);
4111
+ } catch (error) {
4112
+ console.error("[react-naver-maps-kit] failed to clear GPX data layer listeners", error);
4113
+ }
4114
+ data.setMap(null);
4115
+ dataRef.current = null;
4116
+ prevUrlRef.current = null;
4117
+ onDataDestroyRef.current?.();
4118
+ }, []);
4119
+ (0, react.useImperativeHandle)(ref, () => ({
4120
+ getInstance: () => dataRef.current,
4121
+ getAllFeature: (...args) => invokeDataMethod("getAllFeature", ...args),
4122
+ getFeatureById: (...args) => invokeDataMethod("getFeatureById", ...args),
4123
+ getMap: (...args) => invokeDataMethod("getMap", ...args),
4124
+ getStyle: (...args) => invokeDataMethod("getStyle", ...args),
4125
+ overrideStyle: (...args) => invokeDataMethod("overrideStyle", ...args),
4126
+ removeFeature: (...args) => invokeDataMethod("removeFeature", ...args),
4127
+ revertStyle: (...args) => invokeDataMethod("revertStyle", ...args),
4128
+ setStyle: (...args) => invokeDataMethod("setStyle", ...args),
4129
+ toGeoJson: (...args) => invokeDataMethod("toGeoJson", ...args)
4130
+ }), [invokeDataMethod]);
4131
+ const loadAndAddGpx = (0, react.useCallback)(async (data, url, isInitial) => {
4132
+ const controller = new AbortController();
4133
+ abortRef.current = controller;
4134
+ try {
4135
+ const response = await fetch(url, { signal: controller.signal });
4136
+ if (!response.ok) throw new Error(`Failed to fetch GPX: ${response.status} ${response.statusText}`);
4137
+ const xmlDoc = parseXml(await response.text());
4138
+ if (controller.signal.aborted) return;
4139
+ if (!isInitial) data.getAllFeature().forEach((feature) => data.removeFeature(feature));
4140
+ const features = data.addGpx(xmlDoc, props.autoStyle ?? true);
4141
+ prevUrlRef.current = url;
4142
+ props.onFeaturesAdded?.(features);
4143
+ } catch (error) {
4144
+ if (controller.signal.aborted) return;
4145
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to load GPX data.");
4146
+ props.onDataError?.(normalizedError);
4147
+ }
4148
+ }, [
4149
+ props.autoStyle,
4150
+ props.onFeaturesAdded,
4151
+ props.onDataError
4152
+ ]);
4153
+ (0, react.useEffect)(() => {
4154
+ if (sdkStatus !== "ready" || !contextMap || dataRef.current) return;
4155
+ try {
4156
+ const data = new naver.maps.Data();
4157
+ data.setMap(contextMap);
4158
+ if (props.style) data.setStyle(props.style);
4159
+ dataRef.current = data;
4160
+ bindOverlayEventListeners(data, dataEventListenersRef, buildGpxEventBindings(props));
4161
+ props.onDataReady?.(data);
4162
+ loadAndAddGpx(data, props.url, true);
4163
+ } catch (error) {
4164
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Data instance.");
4165
+ props.onDataError?.(normalizedError);
4166
+ }
4167
+ }, [sdkStatus, contextMap]);
4168
+ (0, react.useEffect)(() => {
4169
+ const data = dataRef.current;
4170
+ if (!data || props.url === prevUrlRef.current) return;
4171
+ abortRef.current?.abort();
4172
+ loadAndAddGpx(data, props.url, false);
4173
+ }, [props.url, loadAndAddGpx]);
4174
+ (0, react.useEffect)(() => {
4175
+ const data = dataRef.current;
4176
+ if (!data) return;
4177
+ if (props.style) data.setStyle(props.style);
4178
+ }, [props.style]);
4179
+ (0, react.useEffect)(() => {
4180
+ const data = dataRef.current;
4181
+ if (!data) return;
4182
+ bindOverlayEventListeners(data, dataEventListenersRef, buildGpxEventBindings(props));
4183
+ return () => {
4184
+ removeOverlayEventListeners(dataEventListenersRef.current);
4185
+ dataEventListenersRef.current = [];
4186
+ };
4187
+ }, [props]);
4188
+ (0, react.useEffect)(() => {
4189
+ return () => {
4190
+ teardownData();
4191
+ };
4192
+ }, [teardownData]);
4193
+ return null;
4194
+ });
4195
+ Gpx.displayName = "Gpx";
4196
+
4197
+ //#endregion
4198
+ //#region ../../node_modules/.pnpm/fflate@0.8.2/node_modules/fflate/esm/index.mjs
4199
+ var require$1 = (0, module$1.createRequire)("/");
4200
+ var Worker;
4201
+ try {
4202
+ Worker = require$1("worker_threads").Worker;
4203
+ } catch (e) {}
4204
+ var u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array;
4205
+ var fleb = new u8([
4206
+ 0,
4207
+ 0,
4208
+ 0,
4209
+ 0,
4210
+ 0,
4211
+ 0,
4212
+ 0,
4213
+ 0,
4214
+ 1,
4215
+ 1,
4216
+ 1,
4217
+ 1,
4218
+ 2,
4219
+ 2,
4220
+ 2,
4221
+ 2,
4222
+ 3,
4223
+ 3,
4224
+ 3,
4225
+ 3,
4226
+ 4,
4227
+ 4,
4228
+ 4,
4229
+ 4,
4230
+ 5,
4231
+ 5,
4232
+ 5,
4233
+ 5,
4234
+ 0,
4235
+ 0,
4236
+ 0,
4237
+ 0
4238
+ ]);
4239
+ var fdeb = new u8([
4240
+ 0,
4241
+ 0,
4242
+ 0,
4243
+ 0,
4244
+ 1,
4245
+ 1,
4246
+ 2,
4247
+ 2,
4248
+ 3,
4249
+ 3,
4250
+ 4,
4251
+ 4,
4252
+ 5,
4253
+ 5,
4254
+ 6,
4255
+ 6,
4256
+ 7,
4257
+ 7,
4258
+ 8,
4259
+ 8,
4260
+ 9,
4261
+ 9,
4262
+ 10,
4263
+ 10,
4264
+ 11,
4265
+ 11,
4266
+ 12,
4267
+ 12,
4268
+ 13,
4269
+ 13,
4270
+ 0,
4271
+ 0
4272
+ ]);
4273
+ var clim = new u8([
4274
+ 16,
4275
+ 17,
4276
+ 18,
4277
+ 0,
4278
+ 8,
4279
+ 7,
4280
+ 9,
4281
+ 6,
4282
+ 10,
4283
+ 5,
4284
+ 11,
4285
+ 4,
4286
+ 12,
4287
+ 3,
4288
+ 13,
4289
+ 2,
4290
+ 14,
4291
+ 1,
4292
+ 15
4293
+ ]);
4294
+ var freb = function(eb, start) {
4295
+ var b = new u16(31);
4296
+ for (var i = 0; i < 31; ++i) b[i] = start += 1 << eb[i - 1];
4297
+ var r = new i32(b[30]);
4298
+ for (var i = 1; i < 30; ++i) for (var j = b[i]; j < b[i + 1]; ++j) r[j] = j - b[i] << 5 | i;
4299
+ return {
4300
+ b,
4301
+ r
4302
+ };
4303
+ };
4304
+ var _a = freb(fleb, 2), fl = _a.b, revfl = _a.r;
4305
+ fl[28] = 258, revfl[258] = 28;
4306
+ var _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r;
4307
+ var rev = new u16(32768);
4308
+ for (var i = 0; i < 32768; ++i) {
4309
+ var x = (i & 43690) >> 1 | (i & 21845) << 1;
4310
+ x = (x & 52428) >> 2 | (x & 13107) << 2;
4311
+ x = (x & 61680) >> 4 | (x & 3855) << 4;
4312
+ rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
4313
+ }
4314
+ var hMap = (function(cd, mb, r) {
4315
+ var s = cd.length;
4316
+ var i = 0;
4317
+ var l = new u16(mb);
4318
+ for (; i < s; ++i) if (cd[i]) ++l[cd[i] - 1];
4319
+ var le = new u16(mb);
4320
+ for (i = 1; i < mb; ++i) le[i] = le[i - 1] + l[i - 1] << 1;
4321
+ var co;
4322
+ if (r) {
4323
+ co = new u16(1 << mb);
4324
+ var rvb = 15 - mb;
4325
+ for (i = 0; i < s; ++i) if (cd[i]) {
4326
+ var sv = i << 4 | cd[i];
4327
+ var r_1 = mb - cd[i];
4328
+ var v = le[cd[i] - 1]++ << r_1;
4329
+ for (var m = v | (1 << r_1) - 1; v <= m; ++v) co[rev[v] >> rvb] = sv;
4330
+ }
4331
+ } else {
4332
+ co = new u16(s);
4333
+ for (i = 0; i < s; ++i) if (cd[i]) co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
4334
+ }
4335
+ return co;
4336
+ });
4337
+ var flt = new u8(288);
4338
+ for (var i = 0; i < 144; ++i) flt[i] = 8;
4339
+ for (var i = 144; i < 256; ++i) flt[i] = 9;
4340
+ for (var i = 256; i < 280; ++i) flt[i] = 7;
4341
+ for (var i = 280; i < 288; ++i) flt[i] = 8;
4342
+ var fdt = new u8(32);
4343
+ for (var i = 0; i < 32; ++i) fdt[i] = 5;
4344
+ var flm = /* @__PURE__ */ hMap(flt, 9, 0), flrm = /* @__PURE__ */ hMap(flt, 9, 1);
4345
+ var fdm = /* @__PURE__ */ hMap(fdt, 5, 0), fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
4346
+ var max = function(a) {
4347
+ var m = a[0];
4348
+ for (var i = 1; i < a.length; ++i) if (a[i] > m) m = a[i];
4349
+ return m;
4350
+ };
4351
+ var bits = function(d, p, m) {
4352
+ var o = p / 8 | 0;
4353
+ return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
4354
+ };
4355
+ var bits16 = function(d, p) {
4356
+ var o = p / 8 | 0;
4357
+ return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
4358
+ };
4359
+ var shft = function(p) {
4360
+ return (p + 7) / 8 | 0;
4361
+ };
4362
+ var slc = function(v, s, e) {
4363
+ if (s == null || s < 0) s = 0;
4364
+ if (e == null || e > v.length) e = v.length;
4365
+ return new u8(v.subarray(s, e));
4366
+ };
4367
+ var ec = [
4368
+ "unexpected EOF",
4369
+ "invalid block type",
4370
+ "invalid length/literal",
4371
+ "invalid distance",
4372
+ "stream finished",
4373
+ "no stream handler",
4374
+ ,
4375
+ "no callback",
4376
+ "invalid UTF-8 data",
4377
+ "extra field too long",
4378
+ "date not in range 1980-2099",
4379
+ "filename too long",
4380
+ "stream finishing",
4381
+ "invalid zip data"
4382
+ ];
4383
+ var err = function(ind, msg, nt) {
4384
+ var e = new Error(msg || ec[ind]);
4385
+ e.code = ind;
4386
+ if (Error.captureStackTrace) Error.captureStackTrace(e, err);
4387
+ if (!nt) throw e;
4388
+ return e;
4389
+ };
4390
+ var inflt = function(dat, st, buf, dict) {
4391
+ var sl = dat.length, dl = dict ? dict.length : 0;
4392
+ if (!sl || st.f && !st.l) return buf || new u8(0);
4393
+ var noBuf = !buf;
4394
+ var resize = noBuf || st.i != 2;
4395
+ var noSt = st.i;
4396
+ if (noBuf) buf = new u8(sl * 3);
4397
+ var cbuf = function(l) {
4398
+ var bl = buf.length;
4399
+ if (l > bl) {
4400
+ var nbuf = new u8(Math.max(bl * 2, l));
4401
+ nbuf.set(buf);
4402
+ buf = nbuf;
4403
+ }
4404
+ };
4405
+ var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
4406
+ var tbts = sl * 8;
4407
+ do {
4408
+ if (!lm) {
4409
+ final = bits(dat, pos, 1);
4410
+ var type = bits(dat, pos + 1, 3);
4411
+ pos += 3;
4412
+ if (!type) {
4413
+ var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
4414
+ if (t > sl) {
4415
+ if (noSt) err(0);
4416
+ break;
4417
+ }
4418
+ if (resize) cbuf(bt + l);
4419
+ buf.set(dat.subarray(s, t), bt);
4420
+ st.b = bt += l, st.p = pos = t * 8, st.f = final;
4421
+ continue;
4422
+ } else if (type == 1) lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
4423
+ else if (type == 2) {
4424
+ var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
4425
+ var tl = hLit + bits(dat, pos + 5, 31) + 1;
4426
+ pos += 14;
4427
+ var ldt = new u8(tl);
4428
+ var clt = new u8(19);
4429
+ for (var i = 0; i < hcLen; ++i) clt[clim[i]] = bits(dat, pos + i * 3, 7);
4430
+ pos += hcLen * 3;
4431
+ var clb = max(clt), clbmsk = (1 << clb) - 1;
4432
+ var clm = hMap(clt, clb, 1);
4433
+ for (var i = 0; i < tl;) {
4434
+ var r = clm[bits(dat, pos, clbmsk)];
4435
+ pos += r & 15;
4436
+ var s = r >> 4;
4437
+ if (s < 16) ldt[i++] = s;
4438
+ else {
4439
+ var c = 0, n = 0;
4440
+ if (s == 16) n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
4441
+ else if (s == 17) n = 3 + bits(dat, pos, 7), pos += 3;
4442
+ else if (s == 18) n = 11 + bits(dat, pos, 127), pos += 7;
4443
+ while (n--) ldt[i++] = c;
4444
+ }
4445
+ }
4446
+ var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
4447
+ lbt = max(lt);
4448
+ dbt = max(dt);
4449
+ lm = hMap(lt, lbt, 1);
4450
+ dm = hMap(dt, dbt, 1);
4451
+ } else err(1);
4452
+ if (pos > tbts) {
4453
+ if (noSt) err(0);
4454
+ break;
4455
+ }
4456
+ }
4457
+ if (resize) cbuf(bt + 131072);
4458
+ var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
4459
+ var lpos = pos;
4460
+ for (;; lpos = pos) {
4461
+ var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
4462
+ pos += c & 15;
4463
+ if (pos > tbts) {
4464
+ if (noSt) err(0);
4465
+ break;
4466
+ }
4467
+ if (!c) err(2);
4468
+ if (sym < 256) buf[bt++] = sym;
4469
+ else if (sym == 256) {
4470
+ lpos = pos, lm = null;
4471
+ break;
4472
+ } else {
4473
+ var add = sym - 254;
4474
+ if (sym > 264) {
4475
+ var i = sym - 257, b = fleb[i];
4476
+ add = bits(dat, pos, (1 << b) - 1) + fl[i];
4477
+ pos += b;
4478
+ }
4479
+ var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
4480
+ if (!d) err(3);
4481
+ pos += d & 15;
4482
+ var dt = fd[dsym];
4483
+ if (dsym > 3) {
4484
+ var b = fdeb[dsym];
4485
+ dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
4486
+ }
4487
+ if (pos > tbts) {
4488
+ if (noSt) err(0);
4489
+ break;
4490
+ }
4491
+ if (resize) cbuf(bt + 131072);
4492
+ var end = bt + add;
4493
+ if (bt < dt) {
4494
+ var shift = dl - dt, dend = Math.min(dt, end);
4495
+ if (shift + bt < 0) err(3);
4496
+ for (; bt < dend; ++bt) buf[bt] = dict[shift + bt];
4497
+ }
4498
+ for (; bt < end; ++bt) buf[bt] = buf[bt - dt];
4499
+ }
4500
+ }
4501
+ st.l = lm, st.p = lpos, st.b = bt, st.f = final;
4502
+ if (lm) final = 1, st.m = lbt, st.d = dm, st.n = dbt;
4503
+ } while (!final);
4504
+ return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
4505
+ };
4506
+ var et = /* @__PURE__ */ new u8(0);
4507
+ var b2 = function(d, b) {
4508
+ return d[b] | d[b + 1] << 8;
4509
+ };
4510
+ var b4 = function(d, b) {
4511
+ return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
4512
+ };
4513
+ var b8 = function(d, b) {
4514
+ return b4(d, b) + b4(d, b + 4) * 4294967296;
4515
+ };
4516
+ /**
4517
+ * Expands DEFLATE data with no wrapper
4518
+ * @param data The data to decompress
4519
+ * @param opts The decompression options
4520
+ * @returns The decompressed version of the data
4521
+ */
4522
+ function inflateSync(data, opts) {
4523
+ return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
4524
+ }
4525
+ var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
4526
+ var tds = 0;
4527
+ try {
4528
+ td.decode(et, { stream: true });
4529
+ tds = 1;
4530
+ } catch (e) {}
4531
+ var dutf8 = function(d) {
4532
+ for (var r = "", i = 0;;) {
4533
+ var c = d[i++];
4534
+ var eb = (c > 127) + (c > 223) + (c > 239);
4535
+ if (i + eb > d.length) return {
4536
+ s: r,
4537
+ r: slc(d, i - 1)
4538
+ };
4539
+ if (!eb) r += String.fromCharCode(c);
4540
+ else if (eb == 3) c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
4541
+ else if (eb & 1) r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
4542
+ else r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
4543
+ }
4544
+ };
4545
+ /**
4546
+ * Converts a Uint8Array to a string
4547
+ * @param dat The data to decode to string
4548
+ * @param latin1 Whether or not to interpret the data as Latin-1. This should
4549
+ * not need to be true unless encoding to binary string.
4550
+ * @returns The original UTF-8/Latin-1 string
4551
+ */
4552
+ function strFromU8(dat, latin1) {
4553
+ if (latin1) {
4554
+ var r = "";
4555
+ for (var i = 0; i < dat.length; i += 16384) r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
4556
+ return r;
4557
+ } else if (td) return td.decode(dat);
4558
+ else {
4559
+ var _a = dutf8(dat), s = _a.s, r = _a.r;
4560
+ if (r.length) err(8);
4561
+ return s;
4562
+ }
4563
+ }
4564
+ var slzh = function(d, b) {
4565
+ return b + 30 + b2(d, b + 26) + b2(d, b + 28);
4566
+ };
4567
+ var zh = function(d, b, z) {
4568
+ var fnl = b2(d, b + 28), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl, bs = b4(d, b + 20);
4569
+ var _a = z && bs == 4294967295 ? z64e(d, es) : [
4570
+ bs,
4571
+ b4(d, b + 24),
4572
+ b4(d, b + 42)
4573
+ ], sc = _a[0], su = _a[1], off = _a[2];
4574
+ return [
4575
+ b2(d, b + 10),
4576
+ sc,
4577
+ su,
4578
+ fn,
4579
+ es + b2(d, b + 30) + b2(d, b + 32),
4580
+ off
4581
+ ];
4582
+ };
4583
+ var z64e = function(d, b) {
4584
+ for (; b2(d, b) != 1; b += 4 + b2(d, b + 2));
4585
+ return [
4586
+ b8(d, b + 12),
4587
+ b8(d, b + 4),
4588
+ b8(d, b + 20)
4589
+ ];
4590
+ };
4591
+ /**
4592
+ * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better
4593
+ * performance with more than one file.
4594
+ * @param data The raw compressed ZIP file
4595
+ * @param opts The ZIP extraction options
4596
+ * @returns The decompressed files
4597
+ */
4598
+ function unzipSync(data, opts) {
4599
+ var files = {};
4600
+ var e = data.length - 22;
4601
+ for (; b4(data, e) != 101010256; --e) if (!e || data.length - e > 65558) err(13);
4602
+ var c = b2(data, e + 8);
4603
+ if (!c) return {};
4604
+ var o = b4(data, e + 16);
4605
+ var z = o == 4294967295 || c == 65535;
4606
+ if (z) {
4607
+ var ze = b4(data, e - 12);
4608
+ z = b4(data, ze) == 101075792;
4609
+ if (z) {
4610
+ c = b4(data, ze + 32);
4611
+ o = b4(data, ze + 48);
4612
+ }
4613
+ }
4614
+ var fltr = opts && opts.filter;
4615
+ for (var i = 0; i < c; ++i) {
4616
+ var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);
4617
+ o = no;
4618
+ if (!fltr || fltr({
4619
+ name: fn,
4620
+ size: sc,
4621
+ originalSize: su,
4622
+ compression: c_2
4623
+ })) if (!c_2) files[fn] = slc(data, b, b + sc);
4624
+ else if (c_2 == 8) files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });
4625
+ else err(14, "unknown compression type " + c_2);
4626
+ }
4627
+ return files;
4628
+ }
4629
+
4630
+ //#endregion
4631
+ //#region src/overlays/data/Kmz.tsx
4632
+ function buildKmzEventBindings(props) {
4633
+ return [
4634
+ {
4635
+ eventName: "addfeature",
4636
+ invoke: props.onAddFeature ? (event) => props.onAddFeature?.(event) : void 0
4637
+ },
4638
+ {
4639
+ eventName: "removefeature",
4640
+ invoke: props.onRemoveFeature ? (event) => props.onRemoveFeature?.(event) : void 0
4641
+ },
4642
+ {
4643
+ eventName: "property_changed",
4644
+ invoke: props.onPropertyChanged ? (event) => props.onPropertyChanged?.(event) : void 0
4645
+ },
4646
+ {
4647
+ eventName: "click",
4648
+ invoke: props.onClick ? (event) => props.onClick?.(event) : void 0
4649
+ },
4650
+ {
4651
+ eventName: "dblclick",
4652
+ invoke: props.onDblClick ? (event) => props.onDblClick?.(event) : void 0
4653
+ },
4654
+ {
4655
+ eventName: "rightclick",
4656
+ invoke: props.onRightClick ? (event) => props.onRightClick?.(event) : void 0
4657
+ },
4658
+ {
4659
+ eventName: "mousedown",
4660
+ invoke: props.onMouseDown ? (event) => props.onMouseDown?.(event) : void 0
4661
+ },
4662
+ {
4663
+ eventName: "mouseup",
4664
+ invoke: props.onMouseUp ? (event) => props.onMouseUp?.(event) : void 0
4665
+ },
4666
+ {
4667
+ eventName: "mouseover",
4668
+ invoke: props.onMouseOver ? (event) => props.onMouseOver?.(event) : void 0
4669
+ },
4670
+ {
4671
+ eventName: "mouseout",
4672
+ invoke: props.onMouseOut ? (event) => props.onMouseOut?.(event) : void 0
4673
+ }
4674
+ ];
4675
+ }
4676
+ function extractKmlFromKmz(arrayBuffer) {
4677
+ const files = unzipSync(new Uint8Array(arrayBuffer));
4678
+ const kmlFileName = Object.keys(files).find((name) => name.endsWith(".kml") || name === "doc.kml");
4679
+ if (!kmlFileName) throw new Error("No KML file found in KMZ archive.");
4680
+ const kmlBytes = files[kmlFileName];
4681
+ const kmlString = new TextDecoder("utf-8").decode(kmlBytes);
4682
+ const doc = new DOMParser().parseFromString(kmlString, "application/xml");
4683
+ const parseError = doc.querySelector("parsererror");
4684
+ if (parseError) throw new Error(`KML parse error: ${parseError.textContent}`);
4685
+ return doc;
4686
+ }
4687
+ const Kmz = (0, react.forwardRef)(function KmzInner(props, ref) {
4688
+ const { map: contextMap, sdkStatus } = useNaverMap();
4689
+ const dataRef = (0, react.useRef)(null);
4690
+ const dataEventListenersRef = (0, react.useRef)([]);
4691
+ const onDataDestroyRef = (0, react.useRef)(props.onDataDestroy);
4692
+ const prevUrlRef = (0, react.useRef)(null);
4693
+ const abortRef = (0, react.useRef)(null);
4694
+ (0, react.useEffect)(() => {
4695
+ onDataDestroyRef.current = props.onDataDestroy;
4696
+ }, [props.onDataDestroy]);
4697
+ const invokeDataMethod = (0, react.useCallback)((methodName, ...args) => {
4698
+ const data = dataRef.current;
4699
+ if (!data) return;
4700
+ const method = data[methodName];
4701
+ if (typeof method !== "function") return;
4702
+ return method.apply(data, args);
4703
+ }, []);
4704
+ const teardownData = (0, react.useCallback)(() => {
4705
+ abortRef.current?.abort();
4706
+ abortRef.current = null;
4707
+ const data = dataRef.current;
4708
+ if (!data) return;
4709
+ try {
4710
+ removeOverlayEventListeners(dataEventListenersRef.current);
4711
+ dataEventListenersRef.current = [];
4712
+ naver.maps.Event.clearInstanceListeners(data);
4713
+ } catch (error) {
4714
+ console.error("[react-naver-maps-kit] failed to clear KMZ data layer listeners", error);
4715
+ }
4716
+ data.setMap(null);
4717
+ dataRef.current = null;
4718
+ prevUrlRef.current = null;
4719
+ onDataDestroyRef.current?.();
4720
+ }, []);
4721
+ (0, react.useImperativeHandle)(ref, () => ({
4722
+ getInstance: () => dataRef.current,
4723
+ getAllFeature: (...args) => invokeDataMethod("getAllFeature", ...args),
4724
+ getFeatureById: (...args) => invokeDataMethod("getFeatureById", ...args),
4725
+ getMap: (...args) => invokeDataMethod("getMap", ...args),
4726
+ getStyle: (...args) => invokeDataMethod("getStyle", ...args),
4727
+ overrideStyle: (...args) => invokeDataMethod("overrideStyle", ...args),
4728
+ removeFeature: (...args) => invokeDataMethod("removeFeature", ...args),
4729
+ revertStyle: (...args) => invokeDataMethod("revertStyle", ...args),
4730
+ setStyle: (...args) => invokeDataMethod("setStyle", ...args),
4731
+ toGeoJson: (...args) => invokeDataMethod("toGeoJson", ...args)
4732
+ }), [invokeDataMethod]);
4733
+ const loadAndAddKmz = (0, react.useCallback)(async (data, url, isInitial) => {
4734
+ const controller = new AbortController();
4735
+ abortRef.current = controller;
4736
+ try {
4737
+ const response = await fetch(url, { signal: controller.signal });
4738
+ if (!response.ok) throw new Error(`Failed to fetch KMZ: ${response.status} ${response.statusText}`);
4739
+ const arrayBuffer = await response.arrayBuffer();
4740
+ if (controller.signal.aborted) return;
4741
+ const kmlDoc = extractKmlFromKmz(arrayBuffer);
4742
+ if (!isInitial) data.getAllFeature().forEach((feature) => data.removeFeature(feature));
4743
+ const features = data.addKml(kmlDoc, props.autoStyle ?? true);
4744
+ prevUrlRef.current = url;
4745
+ props.onFeaturesAdded?.(features);
4746
+ } catch (error) {
4747
+ if (controller.signal.aborted) return;
4748
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to load KMZ data.");
4749
+ props.onDataError?.(normalizedError);
4750
+ }
4751
+ }, [
4752
+ props.autoStyle,
4753
+ props.onFeaturesAdded,
4754
+ props.onDataError
4755
+ ]);
4756
+ (0, react.useEffect)(() => {
4757
+ if (sdkStatus !== "ready" || !contextMap || dataRef.current) return;
4758
+ try {
4759
+ const data = new naver.maps.Data();
4760
+ data.setMap(contextMap);
4761
+ if (props.style) data.setStyle(props.style);
4762
+ dataRef.current = data;
4763
+ bindOverlayEventListeners(data, dataEventListenersRef, buildKmzEventBindings(props));
4764
+ props.onDataReady?.(data);
4765
+ loadAndAddKmz(data, props.url, true);
4766
+ } catch (error) {
4767
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to create naver.maps.Data instance.");
4768
+ props.onDataError?.(normalizedError);
4769
+ }
4770
+ }, [sdkStatus, contextMap]);
4771
+ (0, react.useEffect)(() => {
4772
+ const data = dataRef.current;
4773
+ if (!data || props.url === prevUrlRef.current) return;
4774
+ abortRef.current?.abort();
4775
+ loadAndAddKmz(data, props.url, false);
4776
+ }, [props.url, loadAndAddKmz]);
4777
+ (0, react.useEffect)(() => {
4778
+ const data = dataRef.current;
4779
+ if (!data) return;
4780
+ if (props.style) data.setStyle(props.style);
4781
+ }, [props.style]);
4782
+ (0, react.useEffect)(() => {
4783
+ const data = dataRef.current;
4784
+ if (!data) return;
4785
+ bindOverlayEventListeners(data, dataEventListenersRef, buildKmzEventBindings(props));
4786
+ return () => {
4787
+ removeOverlayEventListeners(dataEventListenersRef.current);
4788
+ dataEventListenersRef.current = [];
4789
+ };
4790
+ }, [props]);
4791
+ (0, react.useEffect)(() => {
4792
+ return () => {
4793
+ teardownData();
4794
+ };
4795
+ }, [teardownData]);
4796
+ return null;
4797
+ });
4798
+ Kmz.displayName = "Kmz";
4799
+
3963
4800
  //#endregion
3964
4801
  //#region src/index.ts
3965
- const version = "0.0.1";
4802
+ const version = "1.2.0";
3966
4803
 
3967
4804
  //#endregion
3968
4805
  exports.Circle = Circle;
3969
4806
  exports.ClustererContext = ClustererContext;
3970
4807
  exports.Ellipse = Ellipse;
4808
+ exports.GeoJson = GeoJson;
4809
+ exports.Gpx = Gpx;
3971
4810
  exports.GroundOverlay = GroundOverlay;
3972
4811
  exports.InfoWindow = InfoWindow;
4812
+ exports.Kmz = Kmz;
3973
4813
  exports.Marker = Marker;
3974
4814
  exports.MarkerClusterer = MarkerClusterer;
3975
4815
  exports.NaverMap = NaverMap;