@nine-lab/nine-mu 0.1.290 → 0.1.292

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.290",
3
+ "version": "0.1.292",
4
4
  "description": "AI-Driven Full-Stack Code Fabrication Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/nine-mu.umd.js",
@@ -5,7 +5,7 @@ import '@nine-lab/nine-util';
5
5
  export class NineDiffPopup extends HTMLElement {
6
6
  #dialog = null;
7
7
  #tabContainer = null;
8
- #fileList = []; // 최종 일괄 저장을 위한 데이터 버퍼
8
+ #fileList = []; // 최종 [모두 저장]을 위한 차분 명세 데이터 버퍼
9
9
  #host;
10
10
 
11
11
  constructor() {
@@ -19,8 +19,7 @@ export class NineDiffPopup extends HTMLElement {
19
19
  }
20
20
 
21
21
  /**
22
- * 💡 [기존 방식 복구] 스타일 전량 제거하고,
23
- * 기존 소스처럼 nine-tab 내부에 nine-tab-page 2개를 정적으로 미리 박아 놓습니다.
22
+ * 💡 페이지 외곽 정적 구조 확보
24
23
  */
25
24
  #renderScaffolding() {
26
25
  const customImport = this.getAttribute("css-path") ? `@import "${this.getAttribute("css-path")}";` : "";
@@ -34,12 +33,10 @@ export class NineDiffPopup extends HTMLElement {
34
33
 
35
34
  <nine-dialog>
36
35
  <nine-tab theme="theme-3">
37
- <nine-tab-page caption="MYBATIS">
38
- <nine-diff class="MyBatis"></nine-diff>
39
- </nine-tab-page>
40
- <nine-tab-page caption="JAVASCRIPT">
41
- <nine-diff class="JavaScript"></nine-diff>
42
- </nine-tab-page>
36
+ <nine-tab-page caption="MYBATIS" id="layer_MyBatis"></nine-tab-page>
37
+ <nine-tab-page caption="SERVICE" id="layer_Service"></nine-tab-page>
38
+ <nine-tab-page caption="CONTROLLER" id="layer_Controller"></nine-tab-page>
39
+ <nine-tab-page caption="JAVASCRIPT" id="layer_JavaScript"></nine-tab-page>
43
40
  </nine-tab>
44
41
 
45
42
  <div class="footer">
@@ -62,8 +59,7 @@ export class NineDiffPopup extends HTMLElement {
62
59
  }
63
60
 
64
61
  /**
65
- * 💡 [기존 정적 매핑 방식]
66
- * 동적 생성 없이, 이미 조립되어 들어간 nine-tab 내부의 에디터를 정밀 타격하여 데이터만 꽂습니다.
62
+ * 💡 [ 고정 + 에디터 동적 인스턴싱 엔진]
67
63
  */
68
64
  async data(fileList) {
69
65
  if (!Array.isArray(fileList) || fileList.length === 0) return this;
@@ -77,40 +73,62 @@ export class NineDiffPopup extends HTMLElement {
77
73
  return 'javascript';
78
74
  };
79
75
 
80
- // 💡 중요: nine-tab의 #renderTabs()와 #init()이 끝난
81
- // 섀도우 돔 내부(.tab-pages)로 이사 간 에디터 인스턴스들을 정확하게 추적합니다.
76
+ // 1. 자식 nine-tab의 오리지널 뼈대 파싱이 완벽히 마운트될 때까지 1차 대기
82
77
  setTimeout(() => {
83
- fileList.forEach((file) => {
84
- const { layer, full_path, asis_source, source } = file;
78
+ const activeLayers = fileList.map(f => f.layer);
79
+ const tabButtons = this.#tabContainer.shadowRoot.querySelectorAll('.tab-button');
80
+ const targetLayers = ["MyBatis", "Service", "Controller", "JavaScript"];
85
81
 
86
- // 🎯 렌더링이 완료된 실제 단말 장치는 nine-tab의 shadowRoot 안에 박혀 있습니다.
87
- const diff = this.#tabContainer.shadowRoot.querySelector(`nine-diff.${layer}`);
82
+ targetLayers.forEach((layerName, index) => {
83
+ const currentBtn = tabButtons[index];
84
+ const pageBody = this.#tabContainer.shadowRoot.getElementById(`content${index}`);
88
85
 
89
- if (diff) {
90
- const lang = detectLanguage(full_path);
86
+ if (!pageBody) return;
91
87
 
92
- // 탭 버튼의 상단 텍스트(캡션) 실제 파일명에 맞춰 동기화 시켜줍니다.
93
- const fileName = full_path.split('/').pop() || "Unknown";
94
- const tabButtons = this.#tabContainer.shadowRoot.querySelectorAll('.tab-button');
88
+ if (activeLayers.includes(layerName)) {
89
+ const fileData = fileList.find(f => f.layer === layerName);
90
+ const fileName = fileData.full_path.split('/').pop() || "Unknown";
95
91
 
96
- tabButtons.forEach(btn => {
97
- if (btn.textContent.trim() === layer.toUpperCase()) {
98
- btn.textContent = `${layer.toUpperCase()} (${fileName})`;
99
- }
100
- });
92
+ if (currentBtn) {
93
+ currentBtn.textContent = `${layerName.toUpperCase()} (${fileName})`;
94
+ currentBtn.style.display = "unset";
95
+ }
101
96
 
102
- // 날것의 소스 데이터 바인딩 초기화 실행
103
- diff.initialize(asis_source || "", source || "", lang);
97
+ // 💡 에디터 슬롯 동적 재생성
98
+ pageBody.innerHTML = `<nine-diff class="${layerName}"></nine-diff>`;
104
99
  } else {
105
- trace.error(`❌ 에디터 인스턴스를 찾을 수 없습니다: nine-diff.${layer}`);
100
+ if (currentBtn) {
101
+ currentBtn.style.display = "none";
102
+ currentBtn.classList.remove("active");
103
+ }
104
+ pageBody.innerHTML = "";
106
105
  }
107
106
  });
108
107
 
109
- // 데이터 세팅 완료 nine-tab 초기 포커싱 가동
110
- if (this.#tabContainer && typeof this.#tabContainer.initialize === 'function') {
111
- this.#tabContainer.initialize();
112
- }
113
- }, 100);
108
+ // 2. [결정적 크래시 해결 장치]:
109
+ // 브라우저가 동적 주입된 <nine-diff>의 내부 CodeMirror 인스턴스 렌더링을 완전히 마칠 때까지
110
+ // 프레임 연산을 2단계(더블 틱) 지연시켜 안전 기동 큐를 확보합니다.
111
+ requestAnimationFrame(() => {
112
+ requestAnimationFrame(() => {
113
+ fileList.forEach((file) => {
114
+ const { layer, full_path, asis_source, source } = file;
115
+ const diff = this.#tabContainer.shadowRoot.querySelector(`nine-diff.${layer}`);
116
+
117
+ if (diff && typeof diff.initialize === 'function') {
118
+ const lang = detectLanguage(full_path);
119
+ // 내부 CodeMirror 프레임워크가 완전히 ready 된 시점에 데이터를 바인딩합니다.
120
+ diff.initialize(asis_source || "", source || "", lang);
121
+ }
122
+ });
123
+
124
+ // 데이터 주입 완료 후 첫 활성 탭으로 화면 전환 포커싱
125
+ if (this.#tabContainer && typeof this.#tabContainer.initialize === 'function') {
126
+ this.#tabContainer.initialize();
127
+ }
128
+ });
129
+ });
130
+
131
+ }, 120);
114
132
 
115
133
  return this;
116
134
  }
@@ -123,8 +141,6 @@ export class NineDiffPopup extends HTMLElement {
123
141
 
124
142
  for (const file of this.#fileList) {
125
143
  const { layer, full_path, asis_source } = file;
126
-
127
- // 저장 시점에도 nine-tab의 shadowRoot를 관통하여 데이터를 스캔합니다.
128
144
  const diff = this.#tabContainer.shadowRoot.querySelector(`nine-diff.${layer}`);
129
145
  const currentContent = diff ? diff.getContents() : asis_source;
130
146