ninegrid2 6.916.0 → 6.918.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.
@@ -121655,9 +121655,19 @@ class nxTitle extends HTMLElement {
121655
121655
  }
121656
121656
 
121657
121657
  connectedCallback() {
121658
- this.#init();
121658
+ if (document.readyState === 'loading') { // DOM이 아직 로딩 중이면
121659
+ document.addEventListener('DOMContentLoaded', this.#init);
121660
+ } else { // DOM이 이미 로드 완료되었으면 즉시 실행
121661
+ this.#init();
121662
+ }
121663
+ }
121664
+
121665
+ // 컴포넌트가 DOM에서 제거될 때 이벤트 리스너를 정리
121666
+ disconnectedCallback() {
121667
+ document.removeEventListener('DOMContentLoaded', this.#init);
121659
121668
  }
121660
121669
 
121670
+
121661
121671
  #init = () => {
121662
121672
  this.#generateBreadcrumb(); // 빵 부스러기 데이터 생성 및 최종 렌더링 트리거
121663
121673
  this.#renderer(); // 초기 렌더링 (빵 부스러기 데이터는 아직 없음)
@@ -121651,9 +121651,19 @@ class nxTitle extends HTMLElement {
121651
121651
  }
121652
121652
 
121653
121653
  connectedCallback() {
121654
- this.#init();
121654
+ if (document.readyState === 'loading') { // DOM이 아직 로딩 중이면
121655
+ document.addEventListener('DOMContentLoaded', this.#init);
121656
+ } else { // DOM이 이미 로드 완료되었으면 즉시 실행
121657
+ this.#init();
121658
+ }
121659
+ }
121660
+
121661
+ // 컴포넌트가 DOM에서 제거될 때 이벤트 리스너를 정리
121662
+ disconnectedCallback() {
121663
+ document.removeEventListener('DOMContentLoaded', this.#init);
121655
121664
  }
121656
121665
 
121666
+
121657
121667
  #init = () => {
121658
121668
  this.#generateBreadcrumb(); // 빵 부스러기 데이터 생성 및 최종 렌더링 트리거
121659
121669
  this.#renderer(); // 초기 렌더링 (빵 부스러기 데이터는 아직 없음)
@@ -10,9 +10,19 @@ class nxTitle extends HTMLElement {
10
10
  }
11
11
 
12
12
  connectedCallback() {
13
- this.#init();
13
+ if (document.readyState === 'loading') { // DOM이 아직 로딩 중이면
14
+ document.addEventListener('DOMContentLoaded', this.#init);
15
+ } else { // DOM이 이미 로드 완료되었으면 즉시 실행
16
+ this.#init();
17
+ }
18
+ }
19
+
20
+ // 컴포넌트가 DOM에서 제거될 때 이벤트 리스너를 정리
21
+ disconnectedCallback() {
22
+ document.removeEventListener('DOMContentLoaded', this.#init);
14
23
  }
15
24
 
25
+
16
26
  #init = () => {
17
27
  this.#generateBreadcrumb(); // 빵 부스러기 데이터 생성 및 최종 렌더링 트리거
18
28
  this.#renderer(); // 초기 렌더링 (빵 부스러기 데이터는 아직 없음)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ninegrid2",
3
3
  "type": "module",
4
- "version": "6.916.0",
4
+ "version": "6.918.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
package/src/nx/nxTitle.js CHANGED
@@ -10,9 +10,19 @@ class nxTitle extends HTMLElement {
10
10
  }
11
11
 
12
12
  connectedCallback() {
13
- this.#init();
13
+ if (document.readyState === 'loading') { // DOM이 아직 로딩 중이면
14
+ document.addEventListener('DOMContentLoaded', this.#init);
15
+ } else { // DOM이 이미 로드 완료되었으면 즉시 실행
16
+ this.#init();
17
+ }
18
+ }
19
+
20
+ // 컴포넌트가 DOM에서 제거될 때 이벤트 리스너를 정리
21
+ disconnectedCallback() {
22
+ document.removeEventListener('DOMContentLoaded', this.#init);
14
23
  }
15
24
 
25
+
16
26
  #init = () => {
17
27
  this.#generateBreadcrumb(); // 빵 부스러기 데이터 생성 및 최종 렌더링 트리거
18
28
  this.#renderer(); // 초기 렌더링 (빵 부스러기 데이터는 아직 없음)
@@ -1,388 +0,0 @@
1
- import ninegrid from "../index.js";
2
-
3
- class nxSplitter extends HTMLElement {
4
- #mode;
5
-
6
- constructor() {
7
- super();
8
- this.attachShadow({ mode: "open" });
9
- }
10
-
11
- connectedCallback() {
12
- this.#init();
13
- }
14
-
15
- #detectMode = (el) => {
16
- const prev = el.previousElementSibling;
17
- const next = el.nextElementSibling;
18
-
19
- const prevRect = prev?.getBoundingClientRect();
20
- const nextRect = next?.getBoundingClientRect();
21
-
22
- this.#mode = (!prevRect || !nextRect) || (Math.abs(prevRect.top - nextRect.top) < 5) ? "h" : "v";
23
- };
24
-
25
- #startDrag_BAK = (e) => {
26
- e.preventDefault();
27
- e.stopPropagation();
28
-
29
- const splitterRect = this.getBoundingClientRect();
30
- const isHorizontal = this.#mode === "h";
31
-
32
- // 클릭 지점에서 스플리터 경계까지의 오프셋
33
- const clickOffset = isHorizontal
34
- ? e.clientX - splitterRect.left
35
- : e.clientY - splitterRect.top;
36
-
37
- const dragBar = document.createElement("div");
38
- dragBar.className = `nx-splitter-drag-bar-${this.#mode}`;
39
- Object.assign(dragBar.style, {
40
- position: "absolute",
41
- zIndex: "999",
42
- background: "#666",
43
- opacity: "0.6",
44
- pointerEvents: "none"
45
- });
46
-
47
- const root = this.getRootNode({ composed: true });
48
- // parent는 스플리터의 직접적인 컨테이너 (flex 컨테이너 역할)
49
- const parent = root instanceof ShadowRoot ? root.host : this.parentElement;
50
-
51
- const prev = this.previousElementSibling;
52
- const next = this.nextElementSibling;
53
-
54
- if (!parent || !prev || !next) {
55
- console.warn("Spliter's parent or siblings not found.");
56
- return;
57
- }
58
-
59
- const parentRect = parent.getBoundingClientRect();
60
- const prevRect = prev.getBoundingClientRect();
61
- const nextRect = next.getBoundingClientRect();
62
-
63
- // dragBar의 초기 위치 설정 (parent 기준)
64
- // padding을 고려하지 않고 parentRect를 기준으로 하는 것이 일반적이며,
65
- // 스플리터 컨테이너의 flex-basis가 padding을 포함하는지 여부에 따라 조절.
66
- // 여기서는 parent의 content-box 기준으로 relative 위치를 계산.
67
- let initialPos;
68
- if (isHorizontal) {
69
- initialPos = e.clientX - parentRect.left;
70
- dragBar.style.top = "0";
71
- dragBar.style.left = `${initialPos}px`;
72
- dragBar.style.width = "1px";
73
- dragBar.style.height = "100%";
74
- } else {
75
- initialPos = e.clientY - parentRect.top;
76
- dragBar.style.left = "0";
77
- dragBar.style.top = `${initialPos}px`;
78
- dragBar.style.height = "1px";
79
- dragBar.style.width = "100%";
80
- }
81
-
82
- // Shadow DOM이 있다면 ShadowRoot에, 아니면 일반 DOM에 삽입
83
- (parent.shadowRoot || parent).appendChild(dragBar);
84
-
85
- // 드래그 가능한 범위 (부모 요소 내에서 이전/다음 엘리먼트의 실제 경계 기준)
86
- const minLimit = isHorizontal ? prevRect.left : prevRect.top;
87
- const maxLimit = isHorizontal ? nextRect.right : nextRect.bottom;
88
-
89
- const onMove = moveEvent => {
90
- const clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;
91
- // 드래그 바가 부모 영역을 벗어나지 않도록 클램프
92
- const clampedPos = Math.max(minLimit, Math.min(clientPos, maxLimit));
93
-
94
- // 부모 기준으로 드래그 바의 상대 위치
95
- const relativePos = clampedPos - parentRect[isHorizontal ? "left" : "top"];
96
-
97
- if (isHorizontal) {
98
- dragBar.style.left = `${relativePos}px`;
99
- } else {
100
- dragBar.style.top = `${relativePos}px`;
101
- }
102
- };
103
-
104
- const onUp = upEvent => {
105
- window.removeEventListener("mousemove", onMove);
106
- window.removeEventListener("mouseup", onUp);
107
- dragBar.remove();
108
-
109
- // 최종 드래그 바의 위치를 기준으로 새 크기 계산
110
- const finalDragBarPos = isHorizontal
111
- ? parseFloat(dragBar.style.left)
112
- : parseFloat(dragBar.style.top);
113
-
114
- // 이전 요소의 새로운 크기 (부모의 좌측/상단 경계부터 드래그 바까지)
115
- const newPrevSize = finalDragBarPos;
116
-
117
- // 다음 요소의 새로운 크기 (부모의 전체 크기에서 이전 요소 크기를 뺀 값)
118
- const parentTotalSize = isHorizontal ? parentRect.width : parentRect.height;
119
- const newNextSize = parentTotalSize - newPrevSize;
120
-
121
- // 최소/최대 크기 제약 (예: 1px 미만으로 작아지지 않도록)
122
- const MIN_PANEL_SIZE = 1; // 패널 최소 크기
123
- let finalPrevSize = Math.max(MIN_PANEL_SIZE, newPrevSize);
124
- let finalNextSize = Math.max(MIN_PANEL_SIZE, newNextSize);
125
-
126
- // flex 레이아웃에 직접 width/height를 부여하는 대신 flex-basis를 사용하거나
127
- // flex-grow 비율을 재조정하는 것이 일반적이나, 현재 flex: none; 으로 제어하는 방식을 유지한다면,
128
- // 이와 같이 직접 style.width/height를 설정.
129
- // 하지만 flex 컨테이너 내부에서는 flex-basis를 설정하는 것이 더 바람직합니다.
130
- // 여기서는 기존 코드의 스타일 설정을 유지하면서 값을 정확히 계산.
131
-
132
- // flex-grow 비율로 제어하는 경우
133
- // const currentTotalFlex = parseFloat(getComputedStyle(prev).flexGrow || 0) + parseFloat(getComputedStyle(next).flexGrow || 0);
134
- // prev.style.flexGrow = (newPrevSize / parentTotalSize) * currentTotalFlex;
135
- // next.style.flexGrow = (newNextSize / parentTotalSize) * currentTotalFlex;
136
-
137
- // 기존 flex 값을 저장하고 복원
138
- const originalPrevFlex = prev.style.flex;
139
- const originalNextFlex = next.style.flex;
140
-
141
- // 드래그 중에는 flex를 "none"으로 설정하여 직접 크기 조절
142
- prev.style.flex = "none";
143
- next.style.flex = "none";
144
-
145
- if (isHorizontal) {
146
- prev.style.width = `${finalPrevSize}px`;
147
- next.style.width = `${finalNextSize}px`;
148
- } else {
149
- prev.style.height = `${finalPrevSize}px`;
150
- next.style.height = `${finalNextSize}px`;
151
- }
152
-
153
- // 작업 완료 후 원래 flex 값으로 복원
154
- // 단, width/height가 설정된 경우 flex 속성이 다시 적용되면 겹칠 수 있으므로 주의 필요.
155
- // 일반적으로 flex-basis를 사용하거나, width/height 설정 후 flex-grow/shrink를 기본값으로 돌리는 것을 고려.
156
- prev.style.flex = originalPrevFlex;
157
- next.style.flex = originalNextFlex;
158
- };
159
-
160
- window.addEventListener("mousemove", onMove);
161
- window.addEventListener("mouseup", onUp);
162
- };
163
-
164
- #startDrag = (e) => {
165
-
166
- e.preventDefault(); // 기본 drag/select 동작 제거
167
- e.stopPropagation();
168
-
169
- const splitterRect = this.getBoundingClientRect();
170
- const clickOffset = this.#mode === "h"
171
- ? e.clientX - splitterRect.left
172
- : e.clientY - splitterRect.top;
173
-
174
- //const mode = this.#mode;
175
- const dragBar = document.createElement("div");
176
- dragBar.className = `nx-splitter-drag-bar-${this.#mode}`;
177
-
178
- // 스타일 지정
179
- Object.assign(dragBar.style, {
180
- position: "absolute",
181
- zIndex: "999",
182
- background: "#666",
183
- opacity: "0.6",
184
- pointerEvents: "none"
185
- });
186
-
187
- const root = this.getRootNode({ composed: true });
188
- const parent = root instanceof ShadowRoot ? root.host : this.parentElement || document.body;
189
-
190
- //const parent = this.getRootNode().host || this.parentElement;
191
- const prev = this.previousElementSibling;
192
- const next = this.nextElementSibling;
193
-
194
- if (!parent || !prev || !next) return;
195
-
196
- const parentRect = parent.getBoundingClientRect();
197
- const prevRect = prev.getBoundingClientRect();
198
- const nextRect = next.getBoundingClientRect();
199
-
200
- /**
201
- const clientPos = this.#mode === "h" ? e.clientX : e.clientY;
202
- const position = Math.max(min, Math.min(clientPos, max));
203
- const relative = position - parent.getBoundingClientRect()[this.#mode === "h" ? "left" : "top"];
204
- */
205
-
206
- const left = e.clientX - parentRect.left;
207
- const top = e.clientY - parentRect.top;
208
-
209
- console.log(left, top);
210
-
211
- // 방향별 위치 설정
212
- if (this.#mode === "h") {
213
- dragBar.style.top = "0";
214
- dragBar.style.left = `${left}px`;
215
- dragBar.style.width = "1px";
216
- dragBar.style.height = "100%";
217
- } else {
218
- dragBar.style.left = "0";
219
- dragBar.style.top = `${top}px`;
220
- dragBar.style.height = "1px";
221
- dragBar.style.width = "100%";
222
- }
223
-
224
- // 👇 부모 노드 기준으로 삽입
225
- (parent.shadowRoot || parent).appendChild(dragBar);
226
-
227
- const min = this.#mode === "h" ? prevRect.left : prevRect.top;
228
- const max = this.#mode === "h" ? nextRect.right : nextRect.bottom;
229
-
230
- const onMove = e => {
231
- const clientPos = this.#mode === "h" ? e.clientX : e.clientY;
232
- const position = Math.max(min, Math.min(clientPos, max));
233
-
234
- const relative = position - parent.getBoundingClientRect()[this.#mode === "h" ? "left" : "top"];
235
-
236
- if (this.#mode === "h") {
237
- dragBar.style.left = `${relative}px`;
238
- } else {
239
- dragBar.style.top = `${relative}px`;
240
- }
241
-
242
- console.log(relative);
243
- };
244
-
245
-
246
-
247
- const onUp = (e) => {
248
-
249
- window.removeEventListener("mousemove", onMove);
250
- window.removeEventListener("mouseup", onUp);
251
- dragBar.remove();
252
-
253
-
254
- // 기준: prev + next 너비 합계
255
- const totalSize = this.#mode === "h"
256
- ? prev.offsetWidth + next.offsetWidth
257
- : prev.offsetHeight + next.offsetHeight;
258
-
259
- // prev 기준 상대 거리 (드래그 거리)
260
-
261
- let delta = this.#mode === "h"
262
- ? e.clientX - prev.getBoundingClientRect().left - clickOffset
263
- : e.clientY - prev.getBoundingClientRect().top - clickOffset;
264
- //let delta = dragStartPos - prev.getBoundingClientRect()[this.#mode === "h" ? "left" : "top"];
265
-
266
- const min = 1;
267
- const max = totalSize - 1;
268
- delta = Math.max(min, Math.min(delta, max));
269
-
270
-
271
- const prev1 = prev.style.flex;
272
- const prev2 = next.style.flex;
273
- prev.style.flex = "none";
274
- next.style.flex = "none";
275
-
276
- console.log(delta, totalSize, clickOffset);
277
-
278
- // 📌 사이즈 적용
279
- if (this.#mode === "h") {
280
- prev.style.width = `${delta}px`;
281
- next.style.width = `${totalSize - delta}px`;
282
- } else {
283
- prev.style.height = `${delta}px`;
284
- next.style.height = `${totalSize - delta}px`;
285
- }
286
-
287
- prev.style.flex = prev1;
288
- next.style.flex = prev2;
289
- };
290
-
291
- window.addEventListener("mousemove", onMove);
292
- window.addEventListener("mouseup", onUp);
293
- };
294
-
295
-
296
- #init = () => {
297
- this.#detectMode(this);
298
-
299
- this.classList.add(this.#mode);
300
-
301
- const contents = this.innerHTML.trim();
302
- const gripClass = `grip-${this.#mode}`;
303
- const gripTmpl = (contents === "") ? `<div class="${gripClass}"></div>`: `<div class="${gripClass}"></div><div class="inner-container">${contents}</div><div class="${gripClass}"></div>`;
304
-
305
- this.innerHTML = ""; // 기존 내부 HTML 제거
306
- const htmlTmpl = document.createElement("template");
307
- htmlTmpl.innerHTML = `
308
- <style>
309
- @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxSplitter.css";
310
- ${ninegrid.getCustomPath(this,"nxSplitter.css")}
311
- </style>
312
-
313
- ${gripTmpl}
314
- `;
315
-
316
- this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
317
-
318
- // grip 이벤트 바인딩
319
- this.shadowRoot.querySelectorAll(".grip-h,.grip-v").forEach(el => {
320
- el.addEventListener("mousedown", e => this.#startDrag(e));
321
- });
322
-
323
- this.#prepareLayout();
324
-
325
- window.addEventListener("resize", () => this.#prepareLayout());
326
- };
327
-
328
- #isLastSplitter = () => {
329
- const parent = this.parentElement;
330
- if (!parent) return false;
331
-
332
- const allSplitters = [...parent.querySelectorAll("nx-splitter")];
333
- return allSplitters.at(-1) === this;
334
- };
335
-
336
- #getSiblingSizeSum = () => {
337
- const parent = this.parentElement;
338
- if (!parent) return 0;
339
-
340
- const isHorizontal = this.#mode === "h";
341
-
342
- return Array.from(parent.children).reduce((sum, el) => {
343
- const size = isHorizontal ? el.offsetWidth : el.offsetHeight;
344
- return sum + size;
345
- }, 0);
346
- };
347
-
348
-
349
- #prepareLayout = () => {
350
-
351
- const isHorizontal = this.#mode === "h";
352
- const prev = this.previousElementSibling;
353
- const next = this.nextElementSibling;
354
- const parent = this.parentElement;
355
- if (!prev || !next || !parent) return;
356
-
357
- const currentTotal = this.#getSiblingSizeSum();
358
- const nextTotal = isHorizontal
359
- ? parent.getBoundingClientRect().width
360
- : parent.getBoundingClientRect().height;
361
-
362
- // 현재 패널 크기 측정
363
- const prevSize = isHorizontal ? prev.offsetWidth : prev.offsetHeight;
364
- const nextSize = isHorizontal ? next.offsetWidth : next.offsetHeight;
365
-
366
- // 현재 비율 계산
367
- const newPrevSize = nextTotal * prevSize / currentTotal;
368
- const newNextSize = nextTotal * nextSize / currentTotal;
369
-
370
-
371
- if (isHorizontal) {
372
- prev.style.width = `${newPrevSize}px`;
373
-
374
- if (this.#isLastSplitter()) {
375
- next.style.width = `${newNextSize}px`;
376
- }
377
- } else {
378
- prev.style.height = `${newPrevSize}px`;
379
-
380
- if (this.#isLastSplitter()) {
381
- next.style.height = `${newNextSize}px`;
382
- }
383
- }
384
- };
385
-
386
- }
387
-
388
- customElements.define("nx-splitter", nxSplitter);