@nine-lab/nine-mu 0.1.387 → 0.1.389

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nine-lab/nine-mu",
3
- "version": "0.1.387",
3
+ "version": "0.1.389",
4
4
  "description": "AI-Driven Full-Stack Code Fabrication Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/nine-mu.umd.js",
@@ -1,15 +1,17 @@
1
- import React, { createContext, useEffect, useState, useContext, lazy, Suspense } from 'react';
1
+ import React, { createContext, useState, useContext, lazy, Suspense, useEffect } from 'react';
2
2
  import { Route, Routes } from 'react-router-dom';
3
3
 
4
4
  // ==========================================
5
- // 1. 내부 기능 A: ScreenContext 및 구조
5
+ // 1. 내부 기능 A: ScreenContext 및 전역 공급자 (수출형)
6
6
  // ==========================================
7
7
  const ScreenContext = createContext();
8
8
  export const useScreen = () => useContext(ScreenContext);
9
9
 
10
- const ScreenProvider = ({ children }) => {
10
+ // 🎯 기존 ScreenProvider 이름 변경 전역 동적 데이터 바인딩 셋업
11
+ export const NineScreenProvider = ({ children }) => {
11
12
  const [activeView, setActiveView] = useState('list-wrapper');
12
13
  const [selectedData, setSelectedData] = useState(null);
14
+ const [menuData, setMenuData] = useState([]); // 💡 데이터 통신 허브를 여기로 단일화
13
15
 
14
16
  const goto = (selector, data) => {
15
17
  setActiveView(selector);
@@ -18,7 +20,7 @@ const ScreenProvider = ({ children }) => {
18
20
 
19
21
  return React.createElement(
20
22
  ScreenContext.Provider,
21
- { value: { activeView, selectedData, goto } },
23
+ { value: { activeView, selectedData, goto, menuData, setMenuData } }, // 🎯 데이터 변경 권한까지 자식들에게 공유
22
24
  children
23
25
  );
24
26
  };
@@ -33,14 +35,9 @@ const Default404 = () => {
33
35
  };
34
36
 
35
37
  const createDynamicRoutes = (menuData, projectViews, Custom404) => {
36
- // 기본 404 및 홈 설정
37
38
  const lazyLoad = (viewPath) => {
38
39
  const importer = projectViews[viewPath];
39
-
40
- // 🎯 [404 해결 포인트] 사용자가 등록한 404가 있으면 그걸 쓰고, 없으면 기본 내장 404를 띄웁니다.
41
- if (!importer) {
42
- return Custom404 ? Custom404 : Default404;
43
- }
40
+ if (!importer) return Custom404 ? Custom404 : Default404;
44
41
  return lazy(() => importer());
45
42
  };
46
43
 
@@ -66,7 +63,6 @@ const createDynamicRoutes = (menuData, projectViews, Custom404) => {
66
63
  const sanitizedParts = pathParts.map(part => part.replace(/-/g, "_"));
67
64
  const fullFolderPath = sanitizedParts.join("/");
68
65
 
69
- // 사용자 프로젝트 루트 기준 상대 경로 매핑
70
66
  const componentPath = `./views/${fullFolderPath}/${pascalName}.jsx`;
71
67
 
72
68
  dynamicRoutes.push({
@@ -77,7 +73,6 @@ const createDynamicRoutes = (menuData, projectViews, Custom404) => {
77
73
  });
78
74
  }
79
75
 
80
- // 🎯 [404 해결 포인트] 정의되지 않은 모든 주소(*)는 라우터 레벨에서 404 매핑 컴포넌트로 리다이렉트
81
76
  dynamicRoutes.push({ path: "*", Component: Custom404 ? Custom404 : Default404 });
82
77
  return dynamicRoutes;
83
78
  };
@@ -203,16 +198,16 @@ class NineExceptionHook extends React.Component {
203
198
  }
204
199
 
205
200
  // ==========================================
206
- // 🎯 3. 핵심: 외부 주입형 404 라우팅 기능 탑재
207
- // ==========================================
208
- // ==========================================
209
- // 🎯 3. 최종 완결: 자식 컴포넌트(children)를 수용하는 구조로 변경
201
+ // 🎯 3. 최종 완결: 순수 라우터 에러 실드 역할만 수행
210
202
  // ==========================================
211
203
  export function NineHook({ menuUrl, views, error404, onCatch, fallback, styles, containerStyle }) {
212
- const { menuData, setMenuData } = useContext(ScreenContext) || {};
204
+ // 🎯 상위 최상단 NineScreenProvider가 뿌려주는 주파수 수신
205
+ const context = useContext(ScreenContext);
206
+ const menuData = context ? context.menuData : [];
207
+ const setMenuData = context ? context.setMenuData : null;
208
+
213
209
  const [localMenuData, setLocalMenuData] = useState([]);
214
210
 
215
- // 부모 컨텍스트가 없을 때를 대비한 안전 장치 및 실시간 fetch
216
211
  const fetchRoutes = async () => {
217
212
  if (!menuUrl) return;
218
213
  try {
@@ -220,11 +215,18 @@ export function NineHook({ menuUrl, views, error404, onCatch, fallback, styles,
220
215
  if (response.ok) {
221
216
  const data = await response.json();
222
217
 
223
- // 전역 Context가 있으면 거기에 찔러넣고, 없으면 로컬 스테이트에 저장
224
- if (window.setNineMenuDataGlobal) {
225
- window.setNineMenuDataGlobal(data);
218
+ // 🎯 상위 Context가 존재하면 거기를 갱신시켜 외부 LeftMenu까지 연쇄 반응 트리거
219
+ if (setMenuData) {
220
+ setMenuData((prev) => {
221
+ if (JSON.stringify(prev) === JSON.stringify(data)) return prev;
222
+ console.log("🔥 [Nine-Library] 최상단 NineScreenProvider 데이터 무선 동기화");
223
+ return data;
224
+ });
226
225
  } else {
227
- setLocalMenuData(data);
226
+ setLocalMenuData((prev) => {
227
+ if (JSON.stringify(prev) === JSON.stringify(data)) return prev;
228
+ return data;
229
+ });
228
230
  }
229
231
  }
230
232
  } catch (e) {
@@ -245,7 +247,7 @@ export function NineHook({ menuUrl, views, error404, onCatch, fallback, styles,
245
247
  };
246
248
  }, [menuUrl]);
247
249
 
248
- const targetData = menuData && menuData.length > 0 ? menuData : localMenuData;
250
+ const targetData = setMenuData ? menuData : localMenuData;
249
251
  const dynamicRoutes = createDynamicRoutes(targetData, views, error404);
250
252
 
251
253
  return React.createElement(