@nine-lab/nine-mu 0.1.388 → 0.1.390
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/nine-mu.js +55 -39
- package/dist/nine-mu.js.map +1 -1
- package/dist/nine-mu.umd.js +1 -1
- package/dist/nine-mu.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/components/hook/NineHook.js +50 -43
package/package.json
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import React, { createContext, useState, useContext, lazy, Suspense
|
|
1
|
+
import React, { createContext, useEffect, useState, useContext, lazy, Suspense } 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
|
-
|
|
11
|
-
export const NineScreenProvider = ({ children }) => {
|
|
10
|
+
const ScreenProvider = ({ children }) => {
|
|
12
11
|
const [activeView, setActiveView] = useState('list-wrapper');
|
|
13
12
|
const [selectedData, setSelectedData] = useState(null);
|
|
14
|
-
const [menuData, setMenuData] = useState([]); // 💡 데이터 통신 허브를 여기로 단일화
|
|
15
13
|
|
|
16
14
|
const goto = (selector, data) => {
|
|
17
15
|
setActiveView(selector);
|
|
@@ -20,7 +18,7 @@ export const NineScreenProvider = ({ children }) => {
|
|
|
20
18
|
|
|
21
19
|
return React.createElement(
|
|
22
20
|
ScreenContext.Provider,
|
|
23
|
-
{ value: { activeView, selectedData, goto
|
|
21
|
+
{ value: { activeView, selectedData, goto } },
|
|
24
22
|
children
|
|
25
23
|
);
|
|
26
24
|
};
|
|
@@ -35,9 +33,14 @@ const Default404 = () => {
|
|
|
35
33
|
};
|
|
36
34
|
|
|
37
35
|
const createDynamicRoutes = (menuData, projectViews, Custom404) => {
|
|
36
|
+
// 기본 404 및 홈 설정
|
|
38
37
|
const lazyLoad = (viewPath) => {
|
|
39
38
|
const importer = projectViews[viewPath];
|
|
40
|
-
|
|
39
|
+
|
|
40
|
+
// 🎯 [404 해결 포인트] 사용자가 등록한 404가 있으면 그걸 쓰고, 없으면 기본 내장 404를 띄웁니다.
|
|
41
|
+
if (!importer) {
|
|
42
|
+
return Custom404 ? Custom404 : Default404;
|
|
43
|
+
}
|
|
41
44
|
return lazy(() => importer());
|
|
42
45
|
};
|
|
43
46
|
|
|
@@ -63,6 +66,7 @@ const createDynamicRoutes = (menuData, projectViews, Custom404) => {
|
|
|
63
66
|
const sanitizedParts = pathParts.map(part => part.replace(/-/g, "_"));
|
|
64
67
|
const fullFolderPath = sanitizedParts.join("/");
|
|
65
68
|
|
|
69
|
+
// 사용자 프로젝트 루트 기준 상대 경로 매핑
|
|
66
70
|
const componentPath = `./views/${fullFolderPath}/${pascalName}.jsx`;
|
|
67
71
|
|
|
68
72
|
dynamicRoutes.push({
|
|
@@ -73,6 +77,7 @@ const createDynamicRoutes = (menuData, projectViews, Custom404) => {
|
|
|
73
77
|
});
|
|
74
78
|
}
|
|
75
79
|
|
|
80
|
+
// 🎯 [404 해결 포인트] 정의되지 않은 모든 주소(*)는 라우터 레벨에서 404 매핑 컴포넌트로 리다이렉트
|
|
76
81
|
dynamicRoutes.push({ path: "*", Component: Custom404 ? Custom404 : Default404 });
|
|
77
82
|
return dynamicRoutes;
|
|
78
83
|
};
|
|
@@ -198,15 +203,13 @@ class NineExceptionHook extends React.Component {
|
|
|
198
203
|
}
|
|
199
204
|
|
|
200
205
|
// ==========================================
|
|
201
|
-
// 🎯 3.
|
|
206
|
+
// 🎯 3. 핵심: 외부 주입형 404 라우팅 기능 탑재
|
|
202
207
|
// ==========================================
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const setMenuData =
|
|
208
|
-
|
|
209
|
-
const [localMenuData, setLocalMenuData] = useState([]);
|
|
208
|
+
// ==========================================
|
|
209
|
+
// 🎯 3. 최종 완결: 자식 컴포넌트(children)를 수용하는 구조로 변경
|
|
210
|
+
// ==========================================
|
|
211
|
+
export function NineHook({ children, menuUrl, views, error404, onCatch, fallback, styles, containerStyle }) {
|
|
212
|
+
const [menuData, setMenuData] = useState([]);
|
|
210
213
|
|
|
211
214
|
const fetchRoutes = async () => {
|
|
212
215
|
if (!menuUrl) return;
|
|
@@ -214,20 +217,11 @@ export function NineHook({ menuUrl, views, error404, onCatch, fallback, styles,
|
|
|
214
217
|
const response = await fetch(`${menuUrl}?t=${Date.now()}`);
|
|
215
218
|
if (response.ok) {
|
|
216
219
|
const data = await response.json();
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
console.log("🔥 [Nine-Library] 최상단 NineScreenProvider 데이터 무선 동기화");
|
|
223
|
-
return data;
|
|
224
|
-
});
|
|
225
|
-
} else {
|
|
226
|
-
setLocalMenuData((prev) => {
|
|
227
|
-
if (JSON.stringify(prev) === JSON.stringify(data)) return prev;
|
|
228
|
-
return data;
|
|
229
|
-
});
|
|
230
|
-
}
|
|
220
|
+
setMenuData((prev) => {
|
|
221
|
+
if (JSON.stringify(prev) === JSON.stringify(data)) return prev;
|
|
222
|
+
console.log("🔥 [Nine-Library] routes.json 변경 감지 -> 전체 시스템 동기화");
|
|
223
|
+
return data;
|
|
224
|
+
});
|
|
231
225
|
}
|
|
232
226
|
} catch (e) {
|
|
233
227
|
console.error("[Nine-Library] 런타임 메뉴 동기화 실패:", e);
|
|
@@ -247,24 +241,37 @@ export function NineHook({ menuUrl, views, error404, onCatch, fallback, styles,
|
|
|
247
241
|
};
|
|
248
242
|
}, [menuUrl]);
|
|
249
243
|
|
|
250
|
-
|
|
251
|
-
|
|
244
|
+
// 🎯 [핵심 교정]: 최초 fetch가 완료되기 전(데이터가 없을 때)에는 렌더링을 잠시 멈춥니다.
|
|
245
|
+
if (!menuData || menuData.length === 0) {
|
|
246
|
+
return React.createElement(
|
|
247
|
+
'div',
|
|
248
|
+
{ style: { padding: '25px', color: '#666', fontFamily: 'monospace', background: '#121314', minHeight: '100vh' } },
|
|
249
|
+
'>> Initializing menu matrix telemetry...'
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const dynamicRoutes = createDynamicRoutes(menuData, views, error404);
|
|
252
254
|
|
|
253
255
|
return React.createElement(
|
|
254
|
-
|
|
255
|
-
{
|
|
256
|
+
ScreenProvider,
|
|
257
|
+
{ menuData },
|
|
256
258
|
React.createElement(
|
|
257
|
-
|
|
258
|
-
{
|
|
259
|
+
NineExceptionHook,
|
|
260
|
+
{ onCatch, fallback, styles, containerStyle },
|
|
261
|
+
children,
|
|
259
262
|
React.createElement(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
263
|
+
Suspense,
|
|
264
|
+
{ fallback: React.createElement('div', { style: { padding: '25px', color: '#666', fontFamily: 'monospace' } }, '>> Loading component matrix...') },
|
|
265
|
+
React.createElement(
|
|
266
|
+
Routes,
|
|
267
|
+
null,
|
|
268
|
+
dynamicRoutes.map((route) =>
|
|
269
|
+
React.createElement(Route, {
|
|
270
|
+
key: route.path,
|
|
271
|
+
path: route.path,
|
|
272
|
+
element: React.createElement(route.Component, { key: route.path })
|
|
273
|
+
})
|
|
274
|
+
)
|
|
268
275
|
)
|
|
269
276
|
)
|
|
270
277
|
)
|