ninegrid2 6.874.0 → 6.876.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.
@@ -231,9 +231,9 @@ class aiMyMessage extends HTMLElement
231
231
  // aiProgressMessage 클래스 정의
232
232
  // aiProgressMessage 클래스 정의 수정
233
233
  class aiProgressMessage extends HTMLElement {
234
- #progressData = []; // 진행 상태 데이터를 저장할 배열
235
- #progressElements = new Map(); // 각 진행 단계의 DOM 요소를 저장할 Map
236
- #animationIntervals = new Map(); // 각 항목의 애니메이션 인터벌 ID를 저장할 Map
234
+ #progressData = [];
235
+ #progressElements = new Map();
236
+ #animationIntervals = new Map();
237
237
 
238
238
  constructor() {
239
239
  super();
@@ -257,14 +257,14 @@ class aiProgressMessage extends HTMLElement {
257
257
  * @param {Array<Object>} data - [{id: 'step1', message: '분석중입니다.', completedMessage: '분석이 완료되었습니다.'}, ...]
258
258
  */
259
259
  initialize(data) {
260
- // 초기 상태는 'pending'으로 설정하고, 원본 메시지 저장 (애니메이션용)
261
260
  this.#progressData = data.map(item => ({
262
261
  ...item,
263
262
  status: 'pending',
264
- originalMessage: item.message // 애니메이션을 위해 원본 메시지 저장
263
+ originalMessage: item.message
265
264
  }));
266
265
  setTimeout(() => {
267
- this.#renderProgress();
266
+ this.#renderProgress(); // 초기 렌더링 시 현재 진행 단계를 활성화
267
+ this.#updateCurrentActiveProgress(); // 초기 활성 단계 설정
268
268
  }, 300);
269
269
  }
270
270
 
@@ -276,50 +276,68 @@ class aiProgressMessage extends HTMLElement {
276
276
  updateProgress(id, status) {
277
277
  const itemIndex = this.#progressData.findIndex(item => item.id === id);
278
278
  if (itemIndex > -1) {
279
- // 기존 상태와 다를 경우에만 업데이트
280
279
  if (this.#progressData[itemIndex].status !== status) {
281
280
  this.#progressData[itemIndex].status = status;
282
- this.#updateProgressItem(this.#progressData[itemIndex]);
281
+ this.#updateProgressItem(this.#progressData[itemIndex]); // 개별 항목 업데이트
282
+ this.#updateCurrentActiveProgress(); // 활성 진행 단계 재설정
283
283
  }
284
284
  }
285
285
  }
286
286
 
287
+ // 현재 진행 중인 첫 번째 pending 항목을 찾아 'active' 상태로 만들고 애니메이션 시작
288
+ // 이전에 active였던 항목의 애니메이션은 중지
289
+ #updateCurrentActiveProgress() {
290
+ let foundActive = false;
291
+ this.#progressData.forEach(item => {
292
+ const li = this.#progressElements.get(item.id);
293
+ if (!li) return; // 요소가 아직 렌더링되지 않았으면 스킵
294
+
295
+ // 모든 항목에서 'active' 클래스 제거 및 애니메이션 중지
296
+ li.classList.remove('active');
297
+ if (this.#animationIntervals.has(item.id)) {
298
+ clearInterval(this.#animationIntervals.get(item.id));
299
+ this.#animationIntervals.delete(item.id);
300
+ li.querySelector(".animated-dots").textContent = ''; // 점 제거
301
+ }
302
+
303
+ // 첫 번째 pending 항목을 찾으면 'active'로 설정하고 애니메이션 시작
304
+ if (item.status === 'pending' && !foundActive) {
305
+ li.classList.add('active');
306
+ this.#startAnimation(item);
307
+ foundActive = true;
308
+ }
309
+ });
310
+ }
311
+
287
312
  #renderProgress() {
288
313
  const progressList = this.shadowRoot.querySelector(".progress-list");
289
- progressList.innerHTML = ''; // 기존 목록 초기화
290
- this.#progressElements.clear(); // 기존 요소 Map 초기화
291
- this.#animationIntervals.forEach(intervalId => clearInterval(intervalId)); // 기존 애니메이션 정리
314
+ progressList.innerHTML = '';
315
+ this.#progressElements.clear();
316
+ this.#animationIntervals.forEach(intervalId => clearInterval(intervalId));
292
317
  this.#animationIntervals.clear();
293
318
 
294
319
  this.#progressData.forEach((item, index) => {
295
320
  const li = document.createElement("li");
296
321
  li.setAttribute("data-id", item.id);
297
322
  li.classList.add("progress-item");
298
- // 번호와 초기 메시지 설정
299
323
  li.innerHTML = `
300
324
  <span class="step-number">${index + 1}.</span>
301
- <span class="text">${item.message}</span>
325
+ <span class="text">${item.originalMessage}</span>
302
326
  <span class="animated-dots"></span>
303
- `; // animated-dots 스판 추가
327
+ `;
304
328
  progressList.appendChild(li);
305
329
  this.#progressElements.set(item.id, li);
306
-
307
- // 초기 상태에 따라 업데이트 (특히 애니메이션 시작)
308
- this.#updateProgressItem(item);
330
+ // 초기 렌더링 시에는 'active' 상태는 `#updateCurrentActiveProgress`에서 처리
331
+ this.#updateProgressItemVisuals(item); // 텍스트만 업데이트
309
332
  });
310
333
  }
311
334
 
312
- #updateProgressItem(item) {
335
+ // 항목의 시각적 상태(텍스트, 완료 체크) 업데이트
336
+ #updateProgressItemVisuals(item) {
313
337
  const li = this.#progressElements.get(item.id);
314
338
  if (li) {
315
- // 기존 애니메이션 중지
316
- if (this.#animationIntervals.has(item.id)) {
317
- clearInterval(this.#animationIntervals.get(item.id));
318
- this.#animationIntervals.delete(item.id);
319
- }
320
-
321
- li.classList.remove('pending', 'completed'); // 기존 클래스 제거
322
- li.classList.add(item.status); // 새 상태 클래스 추가
339
+ li.classList.remove('pending', 'completed');
340
+ li.classList.add(item.status);
323
341
 
324
342
  const textSpan = li.querySelector(".text");
325
343
  const dotsSpan = li.querySelector(".animated-dots");
@@ -327,18 +345,32 @@ class aiProgressMessage extends HTMLElement {
327
345
  if (item.status === 'completed') {
328
346
  textSpan.textContent = item.completedMessage;
329
347
  dotsSpan.textContent = ''; // 완료 시 점 제거
330
- } else { // pending 상태일 경우
331
- textSpan.textContent = item.originalMessage; // 원본 메시지로 복원
332
- let dotsCount = 0;
333
- // 애니메이션 시작
334
- const intervalId = setInterval(() => {
335
- dotsCount = (dotsCount + 1) % 4; // 0, 1, 2, 3 반복
336
- dotsSpan.textContent = '.'.repeat(dotsCount);
337
- }, 300); // 300ms마다 점 업데이트
338
- this.#animationIntervals.set(item.id, intervalId);
348
+ } else { // pending 상태
349
+ textSpan.textContent = item.originalMessage;
350
+ // pending이지만 active가 아닌 경우 점 없음 (CSS의 role)
339
351
  }
340
352
  }
341
353
  }
354
+
355
+ // 점 애니메이션 시작 함수
356
+ #startAnimation(item) {
357
+ const li = this.#progressElements.get(item.id);
358
+ if (li) {
359
+ const dotsSpan = li.querySelector(".animated-dots");
360
+ let dotsCount = 0;
361
+ const intervalId = setInterval(() => {
362
+ dotsCount = (dotsCount + 1) % 4; // 0, 1, 2, 3 반복
363
+ dotsSpan.textContent = '.'.repeat(dotsCount);
364
+ }, 300);
365
+ this.#animationIntervals.set(item.id, intervalId);
366
+ }
367
+ }
368
+
369
+ // 개별 항목의 상태 업데이트 (텍스트 변경, 클래스 추가/제거)
370
+ // 애니메이션 시작/중지는 `#updateCurrentActiveProgress`에서 담당
371
+ #updateProgressItem(item) {
372
+ this.#updateProgressItemVisuals(item); // 텍스트와 클래스 업데이트
373
+ }
342
374
  }
343
375
 
344
376
 
@@ -121042,8 +121042,20 @@ class nxTab extends HTMLElement {
121042
121042
  //this.shadowRoot.querySelector('.tab-pages').style.height = this.shadowRoot.querySelector('.tab-page').style.height;
121043
121043
 
121044
121044
  this.switchTabHandler = this.#switchTab.bind(this);
121045
+
121046
+
121047
+ this.tappage = {
121048
+ hide: (v) => {
121049
+ this.shadowRoot.querySelectorAll(".tab-button").forEach((el, i) => {
121050
+ if (el.innerText.trim() === v) {
121051
+ el.style.display = "none";
121052
+ }
121053
+ });
121054
+ }
121055
+ };
121045
121056
  }
121046
121057
 
121058
+
121047
121059
  connectedCallback() {
121048
121060
  this.#init();
121049
121061
  this.dispatchEvent(new CustomEvent(ninegrid.EVENT.TAB_LOAD, { bubbles: true, detail: {} }));
@@ -121868,9 +121880,9 @@ class aiMyMessage extends HTMLElement
121868
121880
  // aiProgressMessage 클래스 정의
121869
121881
  // aiProgressMessage 클래스 정의 수정
121870
121882
  class aiProgressMessage extends HTMLElement {
121871
- #progressData = []; // 진행 상태 데이터를 저장할 배열
121872
- #progressElements = new Map(); // 각 진행 단계의 DOM 요소를 저장할 Map
121873
- #animationIntervals = new Map(); // 각 항목의 애니메이션 인터벌 ID를 저장할 Map
121883
+ #progressData = [];
121884
+ #progressElements = new Map();
121885
+ #animationIntervals = new Map();
121874
121886
 
121875
121887
  constructor() {
121876
121888
  super();
@@ -121894,14 +121906,14 @@ class aiProgressMessage extends HTMLElement {
121894
121906
  * @param {Array<Object>} data - [{id: 'step1', message: '분석중입니다.', completedMessage: '분석이 완료되었습니다.'}, ...]
121895
121907
  */
121896
121908
  initialize(data) {
121897
- // 초기 상태는 'pending'으로 설정하고, 원본 메시지 저장 (애니메이션용)
121898
121909
  this.#progressData = data.map(item => ({
121899
121910
  ...item,
121900
121911
  status: 'pending',
121901
- originalMessage: item.message // 애니메이션을 위해 원본 메시지 저장
121912
+ originalMessage: item.message
121902
121913
  }));
121903
121914
  setTimeout(() => {
121904
- this.#renderProgress();
121915
+ this.#renderProgress(); // 초기 렌더링 시 현재 진행 단계를 활성화
121916
+ this.#updateCurrentActiveProgress(); // 초기 활성 단계 설정
121905
121917
  }, 300);
121906
121918
  }
121907
121919
 
@@ -121913,50 +121925,68 @@ class aiProgressMessage extends HTMLElement {
121913
121925
  updateProgress(id, status) {
121914
121926
  const itemIndex = this.#progressData.findIndex(item => item.id === id);
121915
121927
  if (itemIndex > -1) {
121916
- // 기존 상태와 다를 경우에만 업데이트
121917
121928
  if (this.#progressData[itemIndex].status !== status) {
121918
121929
  this.#progressData[itemIndex].status = status;
121919
- this.#updateProgressItem(this.#progressData[itemIndex]);
121930
+ this.#updateProgressItem(this.#progressData[itemIndex]); // 개별 항목 업데이트
121931
+ this.#updateCurrentActiveProgress(); // 활성 진행 단계 재설정
121920
121932
  }
121921
121933
  }
121922
121934
  }
121923
121935
 
121936
+ // 현재 진행 중인 첫 번째 pending 항목을 찾아 'active' 상태로 만들고 애니메이션 시작
121937
+ // 이전에 active였던 항목의 애니메이션은 중지
121938
+ #updateCurrentActiveProgress() {
121939
+ let foundActive = false;
121940
+ this.#progressData.forEach(item => {
121941
+ const li = this.#progressElements.get(item.id);
121942
+ if (!li) return; // 요소가 아직 렌더링되지 않았으면 스킵
121943
+
121944
+ // 모든 항목에서 'active' 클래스 제거 및 애니메이션 중지
121945
+ li.classList.remove('active');
121946
+ if (this.#animationIntervals.has(item.id)) {
121947
+ clearInterval(this.#animationIntervals.get(item.id));
121948
+ this.#animationIntervals.delete(item.id);
121949
+ li.querySelector(".animated-dots").textContent = ''; // 점 제거
121950
+ }
121951
+
121952
+ // 첫 번째 pending 항목을 찾으면 'active'로 설정하고 애니메이션 시작
121953
+ if (item.status === 'pending' && !foundActive) {
121954
+ li.classList.add('active');
121955
+ this.#startAnimation(item);
121956
+ foundActive = true;
121957
+ }
121958
+ });
121959
+ }
121960
+
121924
121961
  #renderProgress() {
121925
121962
  const progressList = this.shadowRoot.querySelector(".progress-list");
121926
- progressList.innerHTML = ''; // 기존 목록 초기화
121927
- this.#progressElements.clear(); // 기존 요소 Map 초기화
121928
- this.#animationIntervals.forEach(intervalId => clearInterval(intervalId)); // 기존 애니메이션 정리
121963
+ progressList.innerHTML = '';
121964
+ this.#progressElements.clear();
121965
+ this.#animationIntervals.forEach(intervalId => clearInterval(intervalId));
121929
121966
  this.#animationIntervals.clear();
121930
121967
 
121931
121968
  this.#progressData.forEach((item, index) => {
121932
121969
  const li = document.createElement("li");
121933
121970
  li.setAttribute("data-id", item.id);
121934
121971
  li.classList.add("progress-item");
121935
- // 번호와 초기 메시지 설정
121936
121972
  li.innerHTML = `
121937
121973
  <span class="step-number">${index + 1}.</span>
121938
- <span class="text">${item.message}</span>
121974
+ <span class="text">${item.originalMessage}</span>
121939
121975
  <span class="animated-dots"></span>
121940
- `; // animated-dots 스판 추가
121976
+ `;
121941
121977
  progressList.appendChild(li);
121942
121978
  this.#progressElements.set(item.id, li);
121943
-
121944
- // 초기 상태에 따라 업데이트 (특히 애니메이션 시작)
121945
- this.#updateProgressItem(item);
121979
+ // 초기 렌더링 시에는 'active' 상태는 `#updateCurrentActiveProgress`에서 처리
121980
+ this.#updateProgressItemVisuals(item); // 텍스트만 업데이트
121946
121981
  });
121947
121982
  }
121948
121983
 
121949
- #updateProgressItem(item) {
121984
+ // 항목의 시각적 상태(텍스트, 완료 체크) 업데이트
121985
+ #updateProgressItemVisuals(item) {
121950
121986
  const li = this.#progressElements.get(item.id);
121951
121987
  if (li) {
121952
- // 기존 애니메이션 중지
121953
- if (this.#animationIntervals.has(item.id)) {
121954
- clearInterval(this.#animationIntervals.get(item.id));
121955
- this.#animationIntervals.delete(item.id);
121956
- }
121957
-
121958
- li.classList.remove('pending', 'completed'); // 기존 클래스 제거
121959
- li.classList.add(item.status); // 새 상태 클래스 추가
121988
+ li.classList.remove('pending', 'completed');
121989
+ li.classList.add(item.status);
121960
121990
 
121961
121991
  const textSpan = li.querySelector(".text");
121962
121992
  const dotsSpan = li.querySelector(".animated-dots");
@@ -121964,18 +121994,32 @@ class aiProgressMessage extends HTMLElement {
121964
121994
  if (item.status === 'completed') {
121965
121995
  textSpan.textContent = item.completedMessage;
121966
121996
  dotsSpan.textContent = ''; // 완료 시 점 제거
121967
- } else { // pending 상태일 경우
121968
- textSpan.textContent = item.originalMessage; // 원본 메시지로 복원
121969
- let dotsCount = 0;
121970
- // 애니메이션 시작
121971
- const intervalId = setInterval(() => {
121972
- dotsCount = (dotsCount + 1) % 4; // 0, 1, 2, 3 반복
121973
- dotsSpan.textContent = '.'.repeat(dotsCount);
121974
- }, 300); // 300ms마다 점 업데이트
121975
- this.#animationIntervals.set(item.id, intervalId);
121997
+ } else { // pending 상태
121998
+ textSpan.textContent = item.originalMessage;
121999
+ // pending이지만 active가 아닌 경우 점 없음 (CSS의 role)
121976
122000
  }
121977
122001
  }
121978
122002
  }
122003
+
122004
+ // 점 애니메이션 시작 함수
122005
+ #startAnimation(item) {
122006
+ const li = this.#progressElements.get(item.id);
122007
+ if (li) {
122008
+ const dotsSpan = li.querySelector(".animated-dots");
122009
+ let dotsCount = 0;
122010
+ const intervalId = setInterval(() => {
122011
+ dotsCount = (dotsCount + 1) % 4; // 0, 1, 2, 3 반복
122012
+ dotsSpan.textContent = '.'.repeat(dotsCount);
122013
+ }, 300);
122014
+ this.#animationIntervals.set(item.id, intervalId);
122015
+ }
122016
+ }
122017
+
122018
+ // 개별 항목의 상태 업데이트 (텍스트 변경, 클래스 추가/제거)
122019
+ // 애니메이션 시작/중지는 `#updateCurrentActiveProgress`에서 담당
122020
+ #updateProgressItem(item) {
122021
+ this.#updateProgressItemVisuals(item); // 텍스트와 클래스 업데이트
122022
+ }
121979
122023
  }
121980
122024
 
121981
122025
 
@@ -121038,8 +121038,20 @@ class nxTab extends HTMLElement {
121038
121038
  //this.shadowRoot.querySelector('.tab-pages').style.height = this.shadowRoot.querySelector('.tab-page').style.height;
121039
121039
 
121040
121040
  this.switchTabHandler = this.#switchTab.bind(this);
121041
+
121042
+
121043
+ this.tappage = {
121044
+ hide: (v) => {
121045
+ this.shadowRoot.querySelectorAll(".tab-button").forEach((el, i) => {
121046
+ if (el.innerText.trim() === v) {
121047
+ el.style.display = "none";
121048
+ }
121049
+ });
121050
+ }
121051
+ };
121041
121052
  }
121042
121053
 
121054
+
121043
121055
  connectedCallback() {
121044
121056
  this.#init();
121045
121057
  this.dispatchEvent(new CustomEvent(ninegrid.EVENT.TAB_LOAD, { bubbles: true, detail: {} }));
@@ -121864,9 +121876,9 @@ class aiMyMessage extends HTMLElement
121864
121876
  // aiProgressMessage 클래스 정의
121865
121877
  // aiProgressMessage 클래스 정의 수정
121866
121878
  class aiProgressMessage extends HTMLElement {
121867
- #progressData = []; // 진행 상태 데이터를 저장할 배열
121868
- #progressElements = new Map(); // 각 진행 단계의 DOM 요소를 저장할 Map
121869
- #animationIntervals = new Map(); // 각 항목의 애니메이션 인터벌 ID를 저장할 Map
121879
+ #progressData = [];
121880
+ #progressElements = new Map();
121881
+ #animationIntervals = new Map();
121870
121882
 
121871
121883
  constructor() {
121872
121884
  super();
@@ -121890,14 +121902,14 @@ class aiProgressMessage extends HTMLElement {
121890
121902
  * @param {Array<Object>} data - [{id: 'step1', message: '분석중입니다.', completedMessage: '분석이 완료되었습니다.'}, ...]
121891
121903
  */
121892
121904
  initialize(data) {
121893
- // 초기 상태는 'pending'으로 설정하고, 원본 메시지 저장 (애니메이션용)
121894
121905
  this.#progressData = data.map(item => ({
121895
121906
  ...item,
121896
121907
  status: 'pending',
121897
- originalMessage: item.message // 애니메이션을 위해 원본 메시지 저장
121908
+ originalMessage: item.message
121898
121909
  }));
121899
121910
  setTimeout(() => {
121900
- this.#renderProgress();
121911
+ this.#renderProgress(); // 초기 렌더링 시 현재 진행 단계를 활성화
121912
+ this.#updateCurrentActiveProgress(); // 초기 활성 단계 설정
121901
121913
  }, 300);
121902
121914
  }
121903
121915
 
@@ -121909,50 +121921,68 @@ class aiProgressMessage extends HTMLElement {
121909
121921
  updateProgress(id, status) {
121910
121922
  const itemIndex = this.#progressData.findIndex(item => item.id === id);
121911
121923
  if (itemIndex > -1) {
121912
- // 기존 상태와 다를 경우에만 업데이트
121913
121924
  if (this.#progressData[itemIndex].status !== status) {
121914
121925
  this.#progressData[itemIndex].status = status;
121915
- this.#updateProgressItem(this.#progressData[itemIndex]);
121926
+ this.#updateProgressItem(this.#progressData[itemIndex]); // 개별 항목 업데이트
121927
+ this.#updateCurrentActiveProgress(); // 활성 진행 단계 재설정
121916
121928
  }
121917
121929
  }
121918
121930
  }
121919
121931
 
121932
+ // 현재 진행 중인 첫 번째 pending 항목을 찾아 'active' 상태로 만들고 애니메이션 시작
121933
+ // 이전에 active였던 항목의 애니메이션은 중지
121934
+ #updateCurrentActiveProgress() {
121935
+ let foundActive = false;
121936
+ this.#progressData.forEach(item => {
121937
+ const li = this.#progressElements.get(item.id);
121938
+ if (!li) return; // 요소가 아직 렌더링되지 않았으면 스킵
121939
+
121940
+ // 모든 항목에서 'active' 클래스 제거 및 애니메이션 중지
121941
+ li.classList.remove('active');
121942
+ if (this.#animationIntervals.has(item.id)) {
121943
+ clearInterval(this.#animationIntervals.get(item.id));
121944
+ this.#animationIntervals.delete(item.id);
121945
+ li.querySelector(".animated-dots").textContent = ''; // 점 제거
121946
+ }
121947
+
121948
+ // 첫 번째 pending 항목을 찾으면 'active'로 설정하고 애니메이션 시작
121949
+ if (item.status === 'pending' && !foundActive) {
121950
+ li.classList.add('active');
121951
+ this.#startAnimation(item);
121952
+ foundActive = true;
121953
+ }
121954
+ });
121955
+ }
121956
+
121920
121957
  #renderProgress() {
121921
121958
  const progressList = this.shadowRoot.querySelector(".progress-list");
121922
- progressList.innerHTML = ''; // 기존 목록 초기화
121923
- this.#progressElements.clear(); // 기존 요소 Map 초기화
121924
- this.#animationIntervals.forEach(intervalId => clearInterval(intervalId)); // 기존 애니메이션 정리
121959
+ progressList.innerHTML = '';
121960
+ this.#progressElements.clear();
121961
+ this.#animationIntervals.forEach(intervalId => clearInterval(intervalId));
121925
121962
  this.#animationIntervals.clear();
121926
121963
 
121927
121964
  this.#progressData.forEach((item, index) => {
121928
121965
  const li = document.createElement("li");
121929
121966
  li.setAttribute("data-id", item.id);
121930
121967
  li.classList.add("progress-item");
121931
- // 번호와 초기 메시지 설정
121932
121968
  li.innerHTML = `
121933
121969
  <span class="step-number">${index + 1}.</span>
121934
- <span class="text">${item.message}</span>
121970
+ <span class="text">${item.originalMessage}</span>
121935
121971
  <span class="animated-dots"></span>
121936
- `; // animated-dots 스판 추가
121972
+ `;
121937
121973
  progressList.appendChild(li);
121938
121974
  this.#progressElements.set(item.id, li);
121939
-
121940
- // 초기 상태에 따라 업데이트 (특히 애니메이션 시작)
121941
- this.#updateProgressItem(item);
121975
+ // 초기 렌더링 시에는 'active' 상태는 `#updateCurrentActiveProgress`에서 처리
121976
+ this.#updateProgressItemVisuals(item); // 텍스트만 업데이트
121942
121977
  });
121943
121978
  }
121944
121979
 
121945
- #updateProgressItem(item) {
121980
+ // 항목의 시각적 상태(텍스트, 완료 체크) 업데이트
121981
+ #updateProgressItemVisuals(item) {
121946
121982
  const li = this.#progressElements.get(item.id);
121947
121983
  if (li) {
121948
- // 기존 애니메이션 중지
121949
- if (this.#animationIntervals.has(item.id)) {
121950
- clearInterval(this.#animationIntervals.get(item.id));
121951
- this.#animationIntervals.delete(item.id);
121952
- }
121953
-
121954
- li.classList.remove('pending', 'completed'); // 기존 클래스 제거
121955
- li.classList.add(item.status); // 새 상태 클래스 추가
121984
+ li.classList.remove('pending', 'completed');
121985
+ li.classList.add(item.status);
121956
121986
 
121957
121987
  const textSpan = li.querySelector(".text");
121958
121988
  const dotsSpan = li.querySelector(".animated-dots");
@@ -121960,18 +121990,32 @@ class aiProgressMessage extends HTMLElement {
121960
121990
  if (item.status === 'completed') {
121961
121991
  textSpan.textContent = item.completedMessage;
121962
121992
  dotsSpan.textContent = ''; // 완료 시 점 제거
121963
- } else { // pending 상태일 경우
121964
- textSpan.textContent = item.originalMessage; // 원본 메시지로 복원
121965
- let dotsCount = 0;
121966
- // 애니메이션 시작
121967
- const intervalId = setInterval(() => {
121968
- dotsCount = (dotsCount + 1) % 4; // 0, 1, 2, 3 반복
121969
- dotsSpan.textContent = '.'.repeat(dotsCount);
121970
- }, 300); // 300ms마다 점 업데이트
121971
- this.#animationIntervals.set(item.id, intervalId);
121993
+ } else { // pending 상태
121994
+ textSpan.textContent = item.originalMessage;
121995
+ // pending이지만 active가 아닌 경우 점 없음 (CSS의 role)
121972
121996
  }
121973
121997
  }
121974
121998
  }
121999
+
122000
+ // 점 애니메이션 시작 함수
122001
+ #startAnimation(item) {
122002
+ const li = this.#progressElements.get(item.id);
122003
+ if (li) {
122004
+ const dotsSpan = li.querySelector(".animated-dots");
122005
+ let dotsCount = 0;
122006
+ const intervalId = setInterval(() => {
122007
+ dotsCount = (dotsCount + 1) % 4; // 0, 1, 2, 3 반복
122008
+ dotsSpan.textContent = '.'.repeat(dotsCount);
122009
+ }, 300);
122010
+ this.#animationIntervals.set(item.id, intervalId);
122011
+ }
122012
+ }
122013
+
122014
+ // 개별 항목의 상태 업데이트 (텍스트 변경, 클래스 추가/제거)
122015
+ // 애니메이션 시작/중지는 `#updateCurrentActiveProgress`에서 담당
122016
+ #updateProgressItem(item) {
122017
+ this.#updateProgressItemVisuals(item); // 텍스트와 클래스 업데이트
122018
+ }
121975
122019
  }
121976
122020
 
121977
122021
 
package/dist/nx/nxTab.js CHANGED
@@ -19,8 +19,20 @@ class nxTab extends HTMLElement {
19
19
  //this.shadowRoot.querySelector('.tab-pages').style.height = this.shadowRoot.querySelector('.tab-page').style.height;
20
20
 
21
21
  this.switchTabHandler = this.#switchTab.bind(this);
22
+
23
+
24
+ this.tappage = {
25
+ hide: (v) => {
26
+ this.shadowRoot.querySelectorAll(".tab-button").forEach((el, i) => {
27
+ if (el.innerText.trim() === v) {
28
+ el.style.display = "none";
29
+ }
30
+ })
31
+ }
32
+ }
22
33
  }
23
34
 
35
+
24
36
  connectedCallback() {
25
37
  this.#init();
26
38
  this.dispatchEvent(new CustomEvent(ninegrid.EVENT.TAB_LOAD, { bubbles: true, detail: {} }));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ninegrid2",
3
3
  "type": "module",
4
- "version": "6.874.0",
4
+ "version": "6.876.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -231,9 +231,9 @@ class aiMyMessage extends HTMLElement
231
231
  // aiProgressMessage 클래스 정의
232
232
  // aiProgressMessage 클래스 정의 수정
233
233
  class aiProgressMessage extends HTMLElement {
234
- #progressData = []; // 진행 상태 데이터를 저장할 배열
235
- #progressElements = new Map(); // 각 진행 단계의 DOM 요소를 저장할 Map
236
- #animationIntervals = new Map(); // 각 항목의 애니메이션 인터벌 ID를 저장할 Map
234
+ #progressData = [];
235
+ #progressElements = new Map();
236
+ #animationIntervals = new Map();
237
237
 
238
238
  constructor() {
239
239
  super();
@@ -257,14 +257,14 @@ class aiProgressMessage extends HTMLElement {
257
257
  * @param {Array<Object>} data - [{id: 'step1', message: '분석중입니다.', completedMessage: '분석이 완료되었습니다.'}, ...]
258
258
  */
259
259
  initialize(data) {
260
- // 초기 상태는 'pending'으로 설정하고, 원본 메시지 저장 (애니메이션용)
261
260
  this.#progressData = data.map(item => ({
262
261
  ...item,
263
262
  status: 'pending',
264
- originalMessage: item.message // 애니메이션을 위해 원본 메시지 저장
263
+ originalMessage: item.message
265
264
  }));
266
265
  setTimeout(() => {
267
- this.#renderProgress();
266
+ this.#renderProgress(); // 초기 렌더링 시 현재 진행 단계를 활성화
267
+ this.#updateCurrentActiveProgress(); // 초기 활성 단계 설정
268
268
  }, 300);
269
269
  }
270
270
 
@@ -276,50 +276,68 @@ class aiProgressMessage extends HTMLElement {
276
276
  updateProgress(id, status) {
277
277
  const itemIndex = this.#progressData.findIndex(item => item.id === id);
278
278
  if (itemIndex > -1) {
279
- // 기존 상태와 다를 경우에만 업데이트
280
279
  if (this.#progressData[itemIndex].status !== status) {
281
280
  this.#progressData[itemIndex].status = status;
282
- this.#updateProgressItem(this.#progressData[itemIndex]);
281
+ this.#updateProgressItem(this.#progressData[itemIndex]); // 개별 항목 업데이트
282
+ this.#updateCurrentActiveProgress(); // 활성 진행 단계 재설정
283
283
  }
284
284
  }
285
285
  }
286
286
 
287
+ // 현재 진행 중인 첫 번째 pending 항목을 찾아 'active' 상태로 만들고 애니메이션 시작
288
+ // 이전에 active였던 항목의 애니메이션은 중지
289
+ #updateCurrentActiveProgress() {
290
+ let foundActive = false;
291
+ this.#progressData.forEach(item => {
292
+ const li = this.#progressElements.get(item.id);
293
+ if (!li) return; // 요소가 아직 렌더링되지 않았으면 스킵
294
+
295
+ // 모든 항목에서 'active' 클래스 제거 및 애니메이션 중지
296
+ li.classList.remove('active');
297
+ if (this.#animationIntervals.has(item.id)) {
298
+ clearInterval(this.#animationIntervals.get(item.id));
299
+ this.#animationIntervals.delete(item.id);
300
+ li.querySelector(".animated-dots").textContent = ''; // 점 제거
301
+ }
302
+
303
+ // 첫 번째 pending 항목을 찾으면 'active'로 설정하고 애니메이션 시작
304
+ if (item.status === 'pending' && !foundActive) {
305
+ li.classList.add('active');
306
+ this.#startAnimation(item);
307
+ foundActive = true;
308
+ }
309
+ });
310
+ }
311
+
287
312
  #renderProgress() {
288
313
  const progressList = this.shadowRoot.querySelector(".progress-list");
289
- progressList.innerHTML = ''; // 기존 목록 초기화
290
- this.#progressElements.clear(); // 기존 요소 Map 초기화
291
- this.#animationIntervals.forEach(intervalId => clearInterval(intervalId)); // 기존 애니메이션 정리
314
+ progressList.innerHTML = '';
315
+ this.#progressElements.clear();
316
+ this.#animationIntervals.forEach(intervalId => clearInterval(intervalId));
292
317
  this.#animationIntervals.clear();
293
318
 
294
319
  this.#progressData.forEach((item, index) => {
295
320
  const li = document.createElement("li");
296
321
  li.setAttribute("data-id", item.id);
297
322
  li.classList.add("progress-item");
298
- // 번호와 초기 메시지 설정
299
323
  li.innerHTML = `
300
324
  <span class="step-number">${index + 1}.</span>
301
- <span class="text">${item.message}</span>
325
+ <span class="text">${item.originalMessage}</span>
302
326
  <span class="animated-dots"></span>
303
- `; // animated-dots 스판 추가
327
+ `;
304
328
  progressList.appendChild(li);
305
329
  this.#progressElements.set(item.id, li);
306
-
307
- // 초기 상태에 따라 업데이트 (특히 애니메이션 시작)
308
- this.#updateProgressItem(item);
330
+ // 초기 렌더링 시에는 'active' 상태는 `#updateCurrentActiveProgress`에서 처리
331
+ this.#updateProgressItemVisuals(item); // 텍스트만 업데이트
309
332
  });
310
333
  }
311
334
 
312
- #updateProgressItem(item) {
335
+ // 항목의 시각적 상태(텍스트, 완료 체크) 업데이트
336
+ #updateProgressItemVisuals(item) {
313
337
  const li = this.#progressElements.get(item.id);
314
338
  if (li) {
315
- // 기존 애니메이션 중지
316
- if (this.#animationIntervals.has(item.id)) {
317
- clearInterval(this.#animationIntervals.get(item.id));
318
- this.#animationIntervals.delete(item.id);
319
- }
320
-
321
- li.classList.remove('pending', 'completed'); // 기존 클래스 제거
322
- li.classList.add(item.status); // 새 상태 클래스 추가
339
+ li.classList.remove('pending', 'completed');
340
+ li.classList.add(item.status);
323
341
 
324
342
  const textSpan = li.querySelector(".text");
325
343
  const dotsSpan = li.querySelector(".animated-dots");
@@ -327,18 +345,32 @@ class aiProgressMessage extends HTMLElement {
327
345
  if (item.status === 'completed') {
328
346
  textSpan.textContent = item.completedMessage;
329
347
  dotsSpan.textContent = ''; // 완료 시 점 제거
330
- } else { // pending 상태일 경우
331
- textSpan.textContent = item.originalMessage; // 원본 메시지로 복원
332
- let dotsCount = 0;
333
- // 애니메이션 시작
334
- const intervalId = setInterval(() => {
335
- dotsCount = (dotsCount + 1) % 4; // 0, 1, 2, 3 반복
336
- dotsSpan.textContent = '.'.repeat(dotsCount);
337
- }, 300); // 300ms마다 점 업데이트
338
- this.#animationIntervals.set(item.id, intervalId);
348
+ } else { // pending 상태
349
+ textSpan.textContent = item.originalMessage;
350
+ // pending이지만 active가 아닌 경우 점 없음 (CSS의 role)
339
351
  }
340
352
  }
341
353
  }
354
+
355
+ // 점 애니메이션 시작 함수
356
+ #startAnimation(item) {
357
+ const li = this.#progressElements.get(item.id);
358
+ if (li) {
359
+ const dotsSpan = li.querySelector(".animated-dots");
360
+ let dotsCount = 0;
361
+ const intervalId = setInterval(() => {
362
+ dotsCount = (dotsCount + 1) % 4; // 0, 1, 2, 3 반복
363
+ dotsSpan.textContent = '.'.repeat(dotsCount);
364
+ }, 300);
365
+ this.#animationIntervals.set(item.id, intervalId);
366
+ }
367
+ }
368
+
369
+ // 개별 항목의 상태 업데이트 (텍스트 변경, 클래스 추가/제거)
370
+ // 애니메이션 시작/중지는 `#updateCurrentActiveProgress`에서 담당
371
+ #updateProgressItem(item) {
372
+ this.#updateProgressItemVisuals(item); // 텍스트와 클래스 업데이트
373
+ }
342
374
  }
343
375
 
344
376
 
package/src/nx/nxTab.js CHANGED
@@ -19,8 +19,20 @@ class nxTab extends HTMLElement {
19
19
  //this.shadowRoot.querySelector('.tab-pages').style.height = this.shadowRoot.querySelector('.tab-page').style.height;
20
20
 
21
21
  this.switchTabHandler = this.#switchTab.bind(this);
22
+
23
+
24
+ this.tappage = {
25
+ hide: (v) => {
26
+ this.shadowRoot.querySelectorAll(".tab-button").forEach((el, i) => {
27
+ if (el.innerText.trim() === v) {
28
+ el.style.display = "none";
29
+ }
30
+ })
31
+ }
32
+ }
22
33
  }
23
34
 
35
+
24
36
  connectedCallback() {
25
37
  this.#init();
26
38
  this.dispatchEvent(new CustomEvent(ninegrid.EVENT.TAB_LOAD, { bubbles: true, detail: {} }));