ninegrid2 6.862.0 → 6.863.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.
@@ -121167,17 +121167,15 @@ class nxSplitter extends HTMLElement {
121167
121167
  this.#mode = (!prevRect || !nextRect) || (Math.abs(prevRect.top - nextRect.top) < 5) ? "h" : "v";
121168
121168
  };
121169
121169
 
121170
- // 이전 #startDrag_BAK 함수는 삭제하거나 주석 처리합니다.
121171
- // #startDrag_BAK = (...) => { ... }
121172
-
121173
121170
  #startDrag = (e) => {
121174
- e.preventDefault(); // 기본 drag/select 동작 제거
121171
+ e.preventDefault();
121175
121172
  e.stopPropagation();
121176
121173
 
121177
121174
  const splitterRect = this.getBoundingClientRect();
121178
121175
  const isHorizontal = this.#mode === "h";
121179
121176
 
121180
- // 클릭 지점에서 스플리터 경계까지의 오프셋 (이것은 dragBar 초기 위치와는 별개로, 최종 패널 사이즈 계산에 사용됨)
121177
+ // 클릭 지점에서 스플리터 경계까지의 오프셋
121178
+ // 이 값은 최종 패널 사이즈 계산에 사용되며, 드래그 바 초기 위치와는 직접 관련 없음
121181
121179
  isHorizontal
121182
121180
  ? e.clientX - splitterRect.left
121183
121181
  : e.clientY - splitterRect.top;
@@ -121205,15 +121203,14 @@ class nxSplitter extends HTMLElement {
121205
121203
  return;
121206
121204
  }
121207
121205
 
121208
- // dragBar를 먼저 DOM에 추가하여 offsetParent를 확보합니다.
121206
+ // dragBar를 먼저 DOM에 추가하여 offsetParent를 확보
121209
121207
  (parent.shadowRoot || parent).appendChild(dragBar);
121210
121208
 
121211
- // dragBar의 실제 offsetParent (position: absolute의 기준이 되는 요소)
121212
121209
  const dragBarOffsetParent = dragBar.offsetParent;
121213
121210
 
121214
121211
  if (!dragBarOffsetParent) {
121215
121212
  console.error("dragBar's offsetParent could not be determined. Ensure parent or an ancestor has a position property (e.g., relative).");
121216
- dragBar.remove(); // 실패 시 dragBar 제거
121213
+ dragBar.remove();
121217
121214
  return;
121218
121215
  }
121219
121216
 
@@ -121221,7 +121218,6 @@ class nxSplitter extends HTMLElement {
121221
121218
  const prevRect = prev.getBoundingClientRect(); // 뷰포트 기준
121222
121219
  const nextRect = next.getBoundingClientRect(); // 뷰포트 기준
121223
121220
 
121224
-
121225
121221
  // 뷰포트 기준 클릭 위치를 dragBarOffsetParent 기준으로 변환하여 초기 dragBar 위치 설정
121226
121222
  let initialPosInOffsetParent;
121227
121223
  if (isHorizontal) {
@@ -121249,12 +121245,10 @@ class nxSplitter extends HTMLElement {
121249
121245
 
121250
121246
  const onMove = moveEvent => {
121251
121247
  const clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;
121252
- // 뷰포트 기준 클릭 위치를 offsetParent 기준으로 변환
121253
121248
  const currentPosInOffsetParent = isHorizontal
121254
121249
  ? clientPos - dragBarOffsetParentRect.left
121255
121250
  : clientPos - dragBarOffsetParentRect.top;
121256
121251
 
121257
- // 드래그 바가 최소/최대 범위 내에 있도록 클램프
121258
121252
  const clampedPos = Math.max(minLimit, Math.min(currentPosInOffsetParent, maxLimit));
121259
121253
 
121260
121254
  if (isHorizontal) {
@@ -121262,8 +121256,6 @@ class nxSplitter extends HTMLElement {
121262
121256
  } else {
121263
121257
  dragBar.style.top = `${clampedPos}px`;
121264
121258
  }
121265
-
121266
- console.log(clampedPos);
121267
121259
  };
121268
121260
 
121269
121261
  const onUp = (upEvent) => {
@@ -121271,34 +121263,176 @@ class nxSplitter extends HTMLElement {
121271
121263
  window.removeEventListener("mouseup", onUp);
121272
121264
  dragBar.remove();
121273
121265
 
121274
- // 최종 드래그 바의 위치를 offsetParent 기준으로 가져옴
121275
121266
  const finalDragBarPosInOffsetParent = isHorizontal
121276
121267
  ? parseFloat(dragBar.style.left)
121277
121268
  : parseFloat(dragBar.style.top);
121278
121269
 
121279
- // 이전 요소의 새로운 크기 (offsetParent의 시작점부터 드래그 바까지)
121280
- const newPrevSize = finalDragBarPosInOffsetParent;
121270
+ // ⭐⭐ prev와 next의 padding을 고려한 최종 사이즈 계산 ⭐⭐
121271
+ const prevComputedStyle = getComputedStyle(prev);
121272
+ const nextComputedStyle = getComputedStyle(next);
121281
121273
 
121282
- // 다음 요소의 새로운 크기 (offsetParent의 전체 크기에서 이전 요소 크기를 뺀 값)
121283
- const offsetParentTotalSize = isHorizontal
121284
- ? dragBarOffsetParentRect.width
121285
- : dragBarOffsetParentRect.height;
121286
- const newNextSize = offsetParentTotalSize - newPrevSize;
121274
+ if (isHorizontal) {
121275
+ parseFloat(prevComputedStyle.paddingLeft) || 0;
121276
+ parseFloat(nextComputedStyle.paddingRight) || 0;
121277
+ } else {
121278
+ parseFloat(prevComputedStyle.paddingTop) || 0;
121279
+ parseFloat(nextComputedStyle.paddingBottom) || 0;
121280
+ }
121281
+
121282
+ // prev의 새로운 크기: dragBar의 위치 (offsetParent 기준) - prev의 padding-left/top
121283
+ // (prev의 content 시작점까지)
121284
+ finalDragBarPosInOffsetParent - (prevRect[isHorizontal ? 'left' : 'top'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
121285
+
121286
+ // next의 새로운 크기: (offsetParent 전체 크기 - dragBar 위치) - next의 padding-right/bottom
121287
+ (dragBarOffsetParentRect[isHorizontal ? 'width' : 'height'] - finalDragBarPosInOffsetParent);
121288
+
121289
+ // `box-sizing`에 따라 `width`/`height` 설정 방식이 달라짐.
121290
+ // 대부분 `border-box`를 사용하므로, `width`를 설정하면 `padding`이 포함됨.
121291
+ // 따라서 `newPrevInnerSize`와 `newNextInnerSize`는 `padding`을 제외한 `content` 크기가 아니라
121292
+ // 최종적으로 `width`/`height`에 적용될 값이어야 함.
121293
+ // 즉, `padding`이 포함된 전체 `width`/`height`로 계산해야 함.
121294
+
121295
+ // 다시 생각해보면, finalDragBarPosInOffsetParent가 바로 prev의 새로운 width/height가 되어야 합니다.
121296
+ // 왜냐하면 dragBar의 위치가 prev의 끝이기 때문입니다.
121297
+ // 문제는 prev/next에 padding이 있을 때 이 크기를 어떻게 `style.width`/`height`에 반영할지입니다.
121298
+
121299
+ // 가장 일반적인 시나리오: flex-grow 사용 (flex 컨테이너에서 권장)
121300
+ // `prev`와 `next`에 `flex-grow`를 설정하고 `flex-basis: 0;` (혹은 `auto`)를 사용하면,
121301
+ // `flex-grow` 비율로 공간을 나눕니다.
121302
+ // 드래그는 이 `flex-grow` 비율을 조정하는 방식으로 구현하는 것이 가장 깔끔합니다.
121303
+
121304
+ // 현재 prev.style.flex = "none"; next.style.flex = "none"; 방식으로 직접 width/height를 조절하고 있으므로
121305
+ // 이 방식에 맞춰 padding을 고려합니다.
121306
+ // 즉, finalDragBarPosInOffsetParent는 offsetParent의 왼쪽/위쪽 경계부터 dragBar까지의 거리
121307
+ // 이는 곧 prev 요소의 새로운 overall (width/height)가 됩니다.
121308
+
121309
+ // 여기서 오차가 난다면, `prev`와 `next`의 `box-sizing`이 무엇인지 확인해야 합니다.
121310
+ // 만약 `box-sizing: content-box;`라면 `width = content + padding + border`.
121311
+ // 만약 `box-sizing: border-box;`라면 `width = content`.
121312
+ // 일반적으로 CSS Reset이나 프레임워크는 `border-box`를 사용하므로, 이 가정을 따릅니다.
121313
+
121314
+ // `border-box` 가정 시: finalDragBarPosInOffsetParent가 `prev`의 새로운 `width`가 됩니다.
121315
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 `next`의 새로운 `width`가 됩니다.
121316
+ // `padding`은 이 `width` 안에 포함됩니다.
121317
+ // 따라서 별도로 `padding` 값을 빼거나 더할 필요가 없습니다.
121318
+ // 만약 오차가 있다면, `prev` 또는 `next`에 `margin`이 적용되어 있거나,
121319
+ // `parent`에 `gap` 속성 등이 적용되어 있는 것은 아닌지 확인해봐야 합니다.
121320
+
121321
+ // 하지만 사용자께서 padding에서 오차가 난다고 하셨으므로,
121322
+ // `prev`/`next`의 `padding`이 `width`/`height` 계산에 영향을 주는 경우를 상정합니다.
121323
+ // 이 경우 `box-sizing: content-box;` 이거나,
121324
+ // `width`/`height`를 `content` 크기로 설정하고 싶을 때 발생합니다.
121325
+
121326
+ // **새로운 delta 계산 (prev의 최종 너비)**
121327
+ // dragBar의 최종 위치가 offsetParent 기준.
121328
+ // prev.getBoundingClientRect().left - dragBarOffsetParentRect.left : prev의 offsetParent 기준 왼쪽 시작점
121329
+ // clickOffset: 마우스 클릭 지점과 스플리터 바 왼쪽 경계의 차이.
121330
+ // 이 값은 드래그 바의 '컨텐츠' 시작점을 기준으로 한 오프셋으로 간주.
121331
+
121332
+ // 가장 간단한 해결책은 `getBoundingClientRect()`로 얻은 `prevRect.width`와 `nextRect.width`의 합을
121333
+ // `totalSize`로 사용하는 것이 아니라, `parent`의 실제 사용 가능한 공간을 기준으로 삼고,
121334
+ // 드래그 된 `dragBar`의 위치가 해당 공간의 몇 퍼센트를 차지하는지로 `prev`와 `next`의 새로운 `flex-grow`
121335
+ // 비율을 계산하는 것입니다.
121336
+
121337
+ // 현재처럼 직접 width/height를 조절하는 방식에서는
121338
+ // `finalDragBarPosInOffsetParent`가 prev의 새로운 `width`가 되는 것이 맞고,
121339
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 next의 새로운 `width`가 되는 것이 맞습니다.
121340
+ // 만약 padding 때문에 오차가 있다면, 이는 `box-sizing`의 문제이거나,
121341
+ // `getBoundingClientRect()`가 `margin`을 포함하지 않는다는 점 때문일 수 있습니다.
121342
+
121343
+ // **다시 한번 문제의 핵심을 짚어봅시다.**
121344
+ // "dragBar가 그만큼 왼쪽으로 그려져 padding 지우면 정상이야."
121345
+ // 이 문제는 **드래그 바의 초기 위치 문제**입니다. 이 부분은 이미 `dragBar.offsetParent`를 사용하여 해결했습니다.
121346
+
121347
+ // "prev, next가 padding 을 가졌을때는 오차가 있어."
121348
+ // 이 문제는 **최종 `width`/`height`를 `prev`와 `next`에 적용할 때의 오차**입니다.
121349
+ // 즉, `finalPrevSize`와 `finalNextSize`를 계산하는 방식이 문제가 됩니다.
121350
+
121351
+ // `finalDragBarPosInOffsetParent`는 `offsetParent`의 왼쪽/상단 끝에서 `dragBar`까지의 거리입니다.
121352
+ // 이 값이 `prev`의 새로운 너비/높이가 되어야 합니다.
121353
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 `next`의 새로운 너비/높이가 되어야 합니다.
121354
+
121355
+ // 만약 `prev`/`next`가 `padding`을 가질 때 오차가 발생한다면,
121356
+ // 이는 `prev.style.width = \`${finalPrevSize}px\`;`를 적용할 때,
121357
+ // `finalPrevSize`가 `prev`의 `content + padding + border`를 포함하는 `box-sizing: border-box;`일 경우의 크기여야 하는데,
121358
+ // 실제 `prev` 요소의 `box-sizing`이 `content-box`인 경우 `padding`만큼 더 커지기 때문일 수 있습니다.
121359
+
121360
+ // CSS에서 `box-sizing: border-box;`를 모든 요소에 적용하는 것을 강력히 권장합니다.
121361
+ // 예: `* { box-sizing: border-box; }`
121362
+
121363
+ // 만약 `border-box`를 이미 사용하고 있고 여전히 오차가 있다면,
121364
+ // `dragBar`의 `width` (수평 스플리터의 경우) 또는 `height` (수직 스플리터의 경우)를 고려해야 합니다.
121365
+ // 스플리터 자체의 두께만큼 `prev`와 `next` 사이의 공간이 발생하기 때문입니다.
121366
+
121367
+ const splitterThickness = isHorizontal ? splitterRect.width : splitterRect.height; // 스플리터 바의 두께
121368
+ // next의 새로운 크기: (offsetParent 전체 크기 - dragBar 위치) - (스플리터 두께의 절반)
121369
+ offsetParentTotalSize - finalDragBarPosInOffsetParent - (splitterThickness / 2);
121370
+
121371
+ // 스플리터 두께만큼 중앙에서 나누어주는 로직
121372
+ // prev의 끝점은 dragBar의 중앙이 되어야 함
121373
+ // 즉, finalDragBarPosInOffsetParent는 dragBar의 좌측 끝점.
121374
+ // prev의 새로운 크기는 이 dragBar 좌측 끝점에서 prev의 시작점까지의 거리.
121375
+ // 근데 prev의 실제 content box 끝은 dragBar의 중앙까지 와야 한다면,
121376
+ // prev의 끝점에서 dragBar 중앙까지의 거리를 계산.
121377
+
121378
+ // 다시, 드래그 위치 `relative`가 `parent` 기준 스플리터 바의 왼쪽/상단 경계라면
121379
+ // `prev`의 새로운 크기는 이 `relative` 값과 동일해야 합니다.
121380
+ // 그리고 `next`의 새로운 크기는 `parentTotalSize - relative - splitterThickness`가 되어야 합니다.
121381
+ // 여기서 `relative`는 `onMove`에서 계산된 `dragBar.style.left` 또는 `top` 값입니다.
121382
+ // `finalDragBarPosInOffsetParent`는 `relative`와 같은 의미.
121383
+
121384
+ // ⭐ `totalSize` (두 패널의 합계) 대신 `parent`의 사용 가능한 전체 공간을 기준으로
121385
+ // `finalPrevSize`와 `finalNextSize`를 다시 계산합니다.
121386
+ // 이 방식이 `padding`이나 `margin` 같은 외부 요소에 덜 민감합니다.
121387
+
121388
+ // `prev.style.width = Xpx`는 prev의 `content + padding + border`가 Xpx가 된다는 가정 (border-box)
121389
+ // `prev`의 시작점 (offsetParent 기준)
121390
+ const prevStartPosInOffsetParent = isHorizontal
121391
+ ? prevRect.left - dragBarOffsetParentRect.left
121392
+ : prevRect.top - dragBarOffsetParentRect.top;
121393
+
121394
+ // `prev`의 새로운 크기 (스플리터 바의 위치까지)
121395
+ finalPrevSize = finalDragBarPosInOffsetParent - prevStartPosInOffsetParent;
121396
+ // `next`의 새로운 크기 (스플리터 바 이후부터 `offsetParent` 끝까지)
121397
+ // `offsetParentTotalSize`는 `offsetParent`의 전체 너비/높이
121398
+ finalNextSize = offsetParentTotalSize - (finalDragBarPosInOffsetParent + splitterThickness) + (prevStartPosInOffsetParent + finalPrevSize - nextRect[isHorizontal ? 'left' : 'top'] + dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
121399
+ // 이 복잡한 계산은 prev와 next 사이의 간극 (스플리터 두께)을 정확히 반영하기 위함입니다.
121400
+ // `finalPrevSize + finalNextSize + splitterThickness`가 `offsetParentTotalSize`와 일치해야 합니다.
121401
+
121402
+ // ⭐ 최종적으로 계산된 크기:
121403
+ // `finalDragBarPosInOffsetParent`는 `offsetParent`의 시작점에서 `dragBar`의 시작점까지의 거리.
121404
+ // `prev`의 새 너비는 `finalDragBarPosInOffsetParent` 그 자체가 아니라,
121405
+ // `dragBar`가 위치한 곳까지의 `prev`의 너비여야 합니다.
121406
+ // 즉, `finalDragBarPosInOffsetParent`는 `prev`의 끝점이 되는 위치.
121407
+
121408
+ // 다시 한번, `finalDragBarPosInOffsetParent`는 `offsetParent`의 0 지점에서 `dragBar`의 0 지점까지의 거리입니다.
121409
+ // `prev` 요소의 최종 너비는 이 `finalDragBarPosInOffsetParent`에서
121410
+ // `prev` 요소의 `offsetParent` 기준 시작 지점 (`prevRect.left - dragBarOffsetParentRect.left`)을 뺀 값입니다.
121411
+ // 즉, `prev`의 새로운 너비 = `dragBar`의 왼쪽 위치 - `prev`의 왼쪽 위치
121412
+
121413
+ // 그리고 `next`의 새로운 너비 = `next`의 오른쪽 위치 - `dragBar`의 오른쪽 위치
121414
+
121415
+ const newPrevWidthCalculated = finalDragBarPosInOffsetParent - (prevRect[isHorizontal ? 'left' : 'top'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
121416
+ const newNextWidthCalculated = (nextRect[isHorizontal ? 'right' : 'bottom'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']) - (finalDragBarPosInOffsetParent + splitterThickness);
121417
+
121418
+
121419
+ // 최소 크기 제약
121420
+ const MIN_PANEL_SIZE_PX = 1; // 1px 미만으로 작아지지 않도록
121421
+ finalPrevSize = Math.max(MIN_PANEL_SIZE_PX, newPrevWidthCalculated);
121422
+ finalNextSize = Math.max(MIN_PANEL_SIZE_PX, newNextWidthCalculated);
121423
+
121424
+ // 만약 `prev + next + splitter`의 합이 부모의 `content` 사이즈와 일치해야 한다면
121425
+ // `finalNextSize`를 `offsetParentTotalSize - finalPrevSize - splitterThickness`로 계산하는 것이 더 정확할 수 있습니다.
121426
+ // 이렇게 하면 오차가 마지막 패널에 몰아지지만, 합은 정확하게 유지됩니다.
121427
+ finalNextSize = Math.max(MIN_PANEL_SIZE_PX, offsetParentTotalSize - finalPrevSize - splitterThickness);
121287
121428
 
121288
- const MIN_PANEL_SIZE = 1; // 패널 최소 크기
121289
- let finalPrevSize = Math.max(MIN_PANEL_SIZE, newPrevSize);
121290
- let finalNextSize = Math.max(MIN_PANEL_SIZE, newNextSize);
121291
121429
 
121292
- // 기존 flex 값을 저장하고 복원
121293
121430
  const originalPrevFlex = prev.style.flex;
121294
121431
  const originalNextFlex = next.style.flex;
121295
121432
 
121296
- // 드래그 중에는 flex를 "none"으로 설정하여 직접 크기 조절
121297
121433
  prev.style.flex = "none";
121298
121434
  next.style.flex = "none";
121299
121435
 
121300
- console.log(finalPrevSize, finalNextSize);
121301
-
121302
121436
  if (isHorizontal) {
121303
121437
  prev.style.width = `${finalPrevSize}px`;
121304
121438
  next.style.width = `${finalNextSize}px`;
@@ -121307,9 +121441,6 @@ class nxSplitter extends HTMLElement {
121307
121441
  next.style.height = `${finalNextSize}px`;
121308
121442
  }
121309
121443
 
121310
- // 작업 완료 후 원래 flex 값으로 복원
121311
- // 주의: width/height가 설정된 상태에서 flex를 복원하면 충돌할 수 있음.
121312
- // flex-basis나 flex-grow/shrink를 적절히 조절하는 것이 더 견고한 방법.
121313
121444
  prev.style.flex = originalPrevFlex;
121314
121445
  next.style.flex = originalNextFlex;
121315
121446
  };
@@ -121163,17 +121163,15 @@ class nxSplitter extends HTMLElement {
121163
121163
  this.#mode = (!prevRect || !nextRect) || (Math.abs(prevRect.top - nextRect.top) < 5) ? "h" : "v";
121164
121164
  };
121165
121165
 
121166
- // 이전 #startDrag_BAK 함수는 삭제하거나 주석 처리합니다.
121167
- // #startDrag_BAK = (...) => { ... }
121168
-
121169
121166
  #startDrag = (e) => {
121170
- e.preventDefault(); // 기본 drag/select 동작 제거
121167
+ e.preventDefault();
121171
121168
  e.stopPropagation();
121172
121169
 
121173
121170
  const splitterRect = this.getBoundingClientRect();
121174
121171
  const isHorizontal = this.#mode === "h";
121175
121172
 
121176
- // 클릭 지점에서 스플리터 경계까지의 오프셋 (이것은 dragBar 초기 위치와는 별개로, 최종 패널 사이즈 계산에 사용됨)
121173
+ // 클릭 지점에서 스플리터 경계까지의 오프셋
121174
+ // 이 값은 최종 패널 사이즈 계산에 사용되며, 드래그 바 초기 위치와는 직접 관련 없음
121177
121175
  isHorizontal
121178
121176
  ? e.clientX - splitterRect.left
121179
121177
  : e.clientY - splitterRect.top;
@@ -121201,15 +121199,14 @@ class nxSplitter extends HTMLElement {
121201
121199
  return;
121202
121200
  }
121203
121201
 
121204
- // dragBar를 먼저 DOM에 추가하여 offsetParent를 확보합니다.
121202
+ // dragBar를 먼저 DOM에 추가하여 offsetParent를 확보
121205
121203
  (parent.shadowRoot || parent).appendChild(dragBar);
121206
121204
 
121207
- // dragBar의 실제 offsetParent (position: absolute의 기준이 되는 요소)
121208
121205
  const dragBarOffsetParent = dragBar.offsetParent;
121209
121206
 
121210
121207
  if (!dragBarOffsetParent) {
121211
121208
  console.error("dragBar's offsetParent could not be determined. Ensure parent or an ancestor has a position property (e.g., relative).");
121212
- dragBar.remove(); // 실패 시 dragBar 제거
121209
+ dragBar.remove();
121213
121210
  return;
121214
121211
  }
121215
121212
 
@@ -121217,7 +121214,6 @@ class nxSplitter extends HTMLElement {
121217
121214
  const prevRect = prev.getBoundingClientRect(); // 뷰포트 기준
121218
121215
  const nextRect = next.getBoundingClientRect(); // 뷰포트 기준
121219
121216
 
121220
-
121221
121217
  // 뷰포트 기준 클릭 위치를 dragBarOffsetParent 기준으로 변환하여 초기 dragBar 위치 설정
121222
121218
  let initialPosInOffsetParent;
121223
121219
  if (isHorizontal) {
@@ -121245,12 +121241,10 @@ class nxSplitter extends HTMLElement {
121245
121241
 
121246
121242
  const onMove = moveEvent => {
121247
121243
  const clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;
121248
- // 뷰포트 기준 클릭 위치를 offsetParent 기준으로 변환
121249
121244
  const currentPosInOffsetParent = isHorizontal
121250
121245
  ? clientPos - dragBarOffsetParentRect.left
121251
121246
  : clientPos - dragBarOffsetParentRect.top;
121252
121247
 
121253
- // 드래그 바가 최소/최대 범위 내에 있도록 클램프
121254
121248
  const clampedPos = Math.max(minLimit, Math.min(currentPosInOffsetParent, maxLimit));
121255
121249
 
121256
121250
  if (isHorizontal) {
@@ -121258,8 +121252,6 @@ class nxSplitter extends HTMLElement {
121258
121252
  } else {
121259
121253
  dragBar.style.top = `${clampedPos}px`;
121260
121254
  }
121261
-
121262
- console.log(clampedPos);
121263
121255
  };
121264
121256
 
121265
121257
  const onUp = (upEvent) => {
@@ -121267,34 +121259,176 @@ class nxSplitter extends HTMLElement {
121267
121259
  window.removeEventListener("mouseup", onUp);
121268
121260
  dragBar.remove();
121269
121261
 
121270
- // 최종 드래그 바의 위치를 offsetParent 기준으로 가져옴
121271
121262
  const finalDragBarPosInOffsetParent = isHorizontal
121272
121263
  ? parseFloat(dragBar.style.left)
121273
121264
  : parseFloat(dragBar.style.top);
121274
121265
 
121275
- // 이전 요소의 새로운 크기 (offsetParent의 시작점부터 드래그 바까지)
121276
- const newPrevSize = finalDragBarPosInOffsetParent;
121266
+ // ⭐⭐ prev와 next의 padding을 고려한 최종 사이즈 계산 ⭐⭐
121267
+ const prevComputedStyle = getComputedStyle(prev);
121268
+ const nextComputedStyle = getComputedStyle(next);
121277
121269
 
121278
- // 다음 요소의 새로운 크기 (offsetParent의 전체 크기에서 이전 요소 크기를 뺀 값)
121279
- const offsetParentTotalSize = isHorizontal
121280
- ? dragBarOffsetParentRect.width
121281
- : dragBarOffsetParentRect.height;
121282
- const newNextSize = offsetParentTotalSize - newPrevSize;
121270
+ if (isHorizontal) {
121271
+ parseFloat(prevComputedStyle.paddingLeft) || 0;
121272
+ parseFloat(nextComputedStyle.paddingRight) || 0;
121273
+ } else {
121274
+ parseFloat(prevComputedStyle.paddingTop) || 0;
121275
+ parseFloat(nextComputedStyle.paddingBottom) || 0;
121276
+ }
121277
+
121278
+ // prev의 새로운 크기: dragBar의 위치 (offsetParent 기준) - prev의 padding-left/top
121279
+ // (prev의 content 시작점까지)
121280
+ finalDragBarPosInOffsetParent - (prevRect[isHorizontal ? 'left' : 'top'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
121281
+
121282
+ // next의 새로운 크기: (offsetParent 전체 크기 - dragBar 위치) - next의 padding-right/bottom
121283
+ (dragBarOffsetParentRect[isHorizontal ? 'width' : 'height'] - finalDragBarPosInOffsetParent);
121284
+
121285
+ // `box-sizing`에 따라 `width`/`height` 설정 방식이 달라짐.
121286
+ // 대부분 `border-box`를 사용하므로, `width`를 설정하면 `padding`이 포함됨.
121287
+ // 따라서 `newPrevInnerSize`와 `newNextInnerSize`는 `padding`을 제외한 `content` 크기가 아니라
121288
+ // 최종적으로 `width`/`height`에 적용될 값이어야 함.
121289
+ // 즉, `padding`이 포함된 전체 `width`/`height`로 계산해야 함.
121290
+
121291
+ // 다시 생각해보면, finalDragBarPosInOffsetParent가 바로 prev의 새로운 width/height가 되어야 합니다.
121292
+ // 왜냐하면 dragBar의 위치가 prev의 끝이기 때문입니다.
121293
+ // 문제는 prev/next에 padding이 있을 때 이 크기를 어떻게 `style.width`/`height`에 반영할지입니다.
121294
+
121295
+ // 가장 일반적인 시나리오: flex-grow 사용 (flex 컨테이너에서 권장)
121296
+ // `prev`와 `next`에 `flex-grow`를 설정하고 `flex-basis: 0;` (혹은 `auto`)를 사용하면,
121297
+ // `flex-grow` 비율로 공간을 나눕니다.
121298
+ // 드래그는 이 `flex-grow` 비율을 조정하는 방식으로 구현하는 것이 가장 깔끔합니다.
121299
+
121300
+ // 현재 prev.style.flex = "none"; next.style.flex = "none"; 방식으로 직접 width/height를 조절하고 있으므로
121301
+ // 이 방식에 맞춰 padding을 고려합니다.
121302
+ // 즉, finalDragBarPosInOffsetParent는 offsetParent의 왼쪽/위쪽 경계부터 dragBar까지의 거리
121303
+ // 이는 곧 prev 요소의 새로운 overall (width/height)가 됩니다.
121304
+
121305
+ // 여기서 오차가 난다면, `prev`와 `next`의 `box-sizing`이 무엇인지 확인해야 합니다.
121306
+ // 만약 `box-sizing: content-box;`라면 `width = content + padding + border`.
121307
+ // 만약 `box-sizing: border-box;`라면 `width = content`.
121308
+ // 일반적으로 CSS Reset이나 프레임워크는 `border-box`를 사용하므로, 이 가정을 따릅니다.
121309
+
121310
+ // `border-box` 가정 시: finalDragBarPosInOffsetParent가 `prev`의 새로운 `width`가 됩니다.
121311
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 `next`의 새로운 `width`가 됩니다.
121312
+ // `padding`은 이 `width` 안에 포함됩니다.
121313
+ // 따라서 별도로 `padding` 값을 빼거나 더할 필요가 없습니다.
121314
+ // 만약 오차가 있다면, `prev` 또는 `next`에 `margin`이 적용되어 있거나,
121315
+ // `parent`에 `gap` 속성 등이 적용되어 있는 것은 아닌지 확인해봐야 합니다.
121316
+
121317
+ // 하지만 사용자께서 padding에서 오차가 난다고 하셨으므로,
121318
+ // `prev`/`next`의 `padding`이 `width`/`height` 계산에 영향을 주는 경우를 상정합니다.
121319
+ // 이 경우 `box-sizing: content-box;` 이거나,
121320
+ // `width`/`height`를 `content` 크기로 설정하고 싶을 때 발생합니다.
121321
+
121322
+ // **새로운 delta 계산 (prev의 최종 너비)**
121323
+ // dragBar의 최종 위치가 offsetParent 기준.
121324
+ // prev.getBoundingClientRect().left - dragBarOffsetParentRect.left : prev의 offsetParent 기준 왼쪽 시작점
121325
+ // clickOffset: 마우스 클릭 지점과 스플리터 바 왼쪽 경계의 차이.
121326
+ // 이 값은 드래그 바의 '컨텐츠' 시작점을 기준으로 한 오프셋으로 간주.
121327
+
121328
+ // 가장 간단한 해결책은 `getBoundingClientRect()`로 얻은 `prevRect.width`와 `nextRect.width`의 합을
121329
+ // `totalSize`로 사용하는 것이 아니라, `parent`의 실제 사용 가능한 공간을 기준으로 삼고,
121330
+ // 드래그 된 `dragBar`의 위치가 해당 공간의 몇 퍼센트를 차지하는지로 `prev`와 `next`의 새로운 `flex-grow`
121331
+ // 비율을 계산하는 것입니다.
121332
+
121333
+ // 현재처럼 직접 width/height를 조절하는 방식에서는
121334
+ // `finalDragBarPosInOffsetParent`가 prev의 새로운 `width`가 되는 것이 맞고,
121335
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 next의 새로운 `width`가 되는 것이 맞습니다.
121336
+ // 만약 padding 때문에 오차가 있다면, 이는 `box-sizing`의 문제이거나,
121337
+ // `getBoundingClientRect()`가 `margin`을 포함하지 않는다는 점 때문일 수 있습니다.
121338
+
121339
+ // **다시 한번 문제의 핵심을 짚어봅시다.**
121340
+ // "dragBar가 그만큼 왼쪽으로 그려져 padding 지우면 정상이야."
121341
+ // 이 문제는 **드래그 바의 초기 위치 문제**입니다. 이 부분은 이미 `dragBar.offsetParent`를 사용하여 해결했습니다.
121342
+
121343
+ // "prev, next가 padding 을 가졌을때는 오차가 있어."
121344
+ // 이 문제는 **최종 `width`/`height`를 `prev`와 `next`에 적용할 때의 오차**입니다.
121345
+ // 즉, `finalPrevSize`와 `finalNextSize`를 계산하는 방식이 문제가 됩니다.
121346
+
121347
+ // `finalDragBarPosInOffsetParent`는 `offsetParent`의 왼쪽/상단 끝에서 `dragBar`까지의 거리입니다.
121348
+ // 이 값이 `prev`의 새로운 너비/높이가 되어야 합니다.
121349
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 `next`의 새로운 너비/높이가 되어야 합니다.
121350
+
121351
+ // 만약 `prev`/`next`가 `padding`을 가질 때 오차가 발생한다면,
121352
+ // 이는 `prev.style.width = \`${finalPrevSize}px\`;`를 적용할 때,
121353
+ // `finalPrevSize`가 `prev`의 `content + padding + border`를 포함하는 `box-sizing: border-box;`일 경우의 크기여야 하는데,
121354
+ // 실제 `prev` 요소의 `box-sizing`이 `content-box`인 경우 `padding`만큼 더 커지기 때문일 수 있습니다.
121355
+
121356
+ // CSS에서 `box-sizing: border-box;`를 모든 요소에 적용하는 것을 강력히 권장합니다.
121357
+ // 예: `* { box-sizing: border-box; }`
121358
+
121359
+ // 만약 `border-box`를 이미 사용하고 있고 여전히 오차가 있다면,
121360
+ // `dragBar`의 `width` (수평 스플리터의 경우) 또는 `height` (수직 스플리터의 경우)를 고려해야 합니다.
121361
+ // 스플리터 자체의 두께만큼 `prev`와 `next` 사이의 공간이 발생하기 때문입니다.
121362
+
121363
+ const splitterThickness = isHorizontal ? splitterRect.width : splitterRect.height; // 스플리터 바의 두께
121364
+ // next의 새로운 크기: (offsetParent 전체 크기 - dragBar 위치) - (스플리터 두께의 절반)
121365
+ offsetParentTotalSize - finalDragBarPosInOffsetParent - (splitterThickness / 2);
121366
+
121367
+ // 스플리터 두께만큼 중앙에서 나누어주는 로직
121368
+ // prev의 끝점은 dragBar의 중앙이 되어야 함
121369
+ // 즉, finalDragBarPosInOffsetParent는 dragBar의 좌측 끝점.
121370
+ // prev의 새로운 크기는 이 dragBar 좌측 끝점에서 prev의 시작점까지의 거리.
121371
+ // 근데 prev의 실제 content box 끝은 dragBar의 중앙까지 와야 한다면,
121372
+ // prev의 끝점에서 dragBar 중앙까지의 거리를 계산.
121373
+
121374
+ // 다시, 드래그 위치 `relative`가 `parent` 기준 스플리터 바의 왼쪽/상단 경계라면
121375
+ // `prev`의 새로운 크기는 이 `relative` 값과 동일해야 합니다.
121376
+ // 그리고 `next`의 새로운 크기는 `parentTotalSize - relative - splitterThickness`가 되어야 합니다.
121377
+ // 여기서 `relative`는 `onMove`에서 계산된 `dragBar.style.left` 또는 `top` 값입니다.
121378
+ // `finalDragBarPosInOffsetParent`는 `relative`와 같은 의미.
121379
+
121380
+ // ⭐ `totalSize` (두 패널의 합계) 대신 `parent`의 사용 가능한 전체 공간을 기준으로
121381
+ // `finalPrevSize`와 `finalNextSize`를 다시 계산합니다.
121382
+ // 이 방식이 `padding`이나 `margin` 같은 외부 요소에 덜 민감합니다.
121383
+
121384
+ // `prev.style.width = Xpx`는 prev의 `content + padding + border`가 Xpx가 된다는 가정 (border-box)
121385
+ // `prev`의 시작점 (offsetParent 기준)
121386
+ const prevStartPosInOffsetParent = isHorizontal
121387
+ ? prevRect.left - dragBarOffsetParentRect.left
121388
+ : prevRect.top - dragBarOffsetParentRect.top;
121389
+
121390
+ // `prev`의 새로운 크기 (스플리터 바의 위치까지)
121391
+ finalPrevSize = finalDragBarPosInOffsetParent - prevStartPosInOffsetParent;
121392
+ // `next`의 새로운 크기 (스플리터 바 이후부터 `offsetParent` 끝까지)
121393
+ // `offsetParentTotalSize`는 `offsetParent`의 전체 너비/높이
121394
+ finalNextSize = offsetParentTotalSize - (finalDragBarPosInOffsetParent + splitterThickness) + (prevStartPosInOffsetParent + finalPrevSize - nextRect[isHorizontal ? 'left' : 'top'] + dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
121395
+ // 이 복잡한 계산은 prev와 next 사이의 간극 (스플리터 두께)을 정확히 반영하기 위함입니다.
121396
+ // `finalPrevSize + finalNextSize + splitterThickness`가 `offsetParentTotalSize`와 일치해야 합니다.
121397
+
121398
+ // ⭐ 최종적으로 계산된 크기:
121399
+ // `finalDragBarPosInOffsetParent`는 `offsetParent`의 시작점에서 `dragBar`의 시작점까지의 거리.
121400
+ // `prev`의 새 너비는 `finalDragBarPosInOffsetParent` 그 자체가 아니라,
121401
+ // `dragBar`가 위치한 곳까지의 `prev`의 너비여야 합니다.
121402
+ // 즉, `finalDragBarPosInOffsetParent`는 `prev`의 끝점이 되는 위치.
121403
+
121404
+ // 다시 한번, `finalDragBarPosInOffsetParent`는 `offsetParent`의 0 지점에서 `dragBar`의 0 지점까지의 거리입니다.
121405
+ // `prev` 요소의 최종 너비는 이 `finalDragBarPosInOffsetParent`에서
121406
+ // `prev` 요소의 `offsetParent` 기준 시작 지점 (`prevRect.left - dragBarOffsetParentRect.left`)을 뺀 값입니다.
121407
+ // 즉, `prev`의 새로운 너비 = `dragBar`의 왼쪽 위치 - `prev`의 왼쪽 위치
121408
+
121409
+ // 그리고 `next`의 새로운 너비 = `next`의 오른쪽 위치 - `dragBar`의 오른쪽 위치
121410
+
121411
+ const newPrevWidthCalculated = finalDragBarPosInOffsetParent - (prevRect[isHorizontal ? 'left' : 'top'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
121412
+ const newNextWidthCalculated = (nextRect[isHorizontal ? 'right' : 'bottom'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']) - (finalDragBarPosInOffsetParent + splitterThickness);
121413
+
121414
+
121415
+ // 최소 크기 제약
121416
+ const MIN_PANEL_SIZE_PX = 1; // 1px 미만으로 작아지지 않도록
121417
+ finalPrevSize = Math.max(MIN_PANEL_SIZE_PX, newPrevWidthCalculated);
121418
+ finalNextSize = Math.max(MIN_PANEL_SIZE_PX, newNextWidthCalculated);
121419
+
121420
+ // 만약 `prev + next + splitter`의 합이 부모의 `content` 사이즈와 일치해야 한다면
121421
+ // `finalNextSize`를 `offsetParentTotalSize - finalPrevSize - splitterThickness`로 계산하는 것이 더 정확할 수 있습니다.
121422
+ // 이렇게 하면 오차가 마지막 패널에 몰아지지만, 합은 정확하게 유지됩니다.
121423
+ finalNextSize = Math.max(MIN_PANEL_SIZE_PX, offsetParentTotalSize - finalPrevSize - splitterThickness);
121283
121424
 
121284
- const MIN_PANEL_SIZE = 1; // 패널 최소 크기
121285
- let finalPrevSize = Math.max(MIN_PANEL_SIZE, newPrevSize);
121286
- let finalNextSize = Math.max(MIN_PANEL_SIZE, newNextSize);
121287
121425
 
121288
- // 기존 flex 값을 저장하고 복원
121289
121426
  const originalPrevFlex = prev.style.flex;
121290
121427
  const originalNextFlex = next.style.flex;
121291
121428
 
121292
- // 드래그 중에는 flex를 "none"으로 설정하여 직접 크기 조절
121293
121429
  prev.style.flex = "none";
121294
121430
  next.style.flex = "none";
121295
121431
 
121296
- console.log(finalPrevSize, finalNextSize);
121297
-
121298
121432
  if (isHorizontal) {
121299
121433
  prev.style.width = `${finalPrevSize}px`;
121300
121434
  next.style.width = `${finalNextSize}px`;
@@ -121303,9 +121437,6 @@ class nxSplitter extends HTMLElement {
121303
121437
  next.style.height = `${finalNextSize}px`;
121304
121438
  }
121305
121439
 
121306
- // 작업 완료 후 원래 flex 값으로 복원
121307
- // 주의: width/height가 설정된 상태에서 flex를 복원하면 충돌할 수 있음.
121308
- // flex-basis나 flex-grow/shrink를 적절히 조절하는 것이 더 견고한 방법.
121309
121440
  prev.style.flex = originalPrevFlex;
121310
121441
  next.style.flex = originalNextFlex;
121311
121442
  };
@@ -22,17 +22,15 @@ class nxSplitter extends HTMLElement {
22
22
  this.#mode = (!prevRect || !nextRect) || (Math.abs(prevRect.top - nextRect.top) < 5) ? "h" : "v";
23
23
  };
24
24
 
25
- // 이전 #startDrag_BAK 함수는 삭제하거나 주석 처리합니다.
26
- // #startDrag_BAK = (...) => { ... }
27
-
28
25
  #startDrag = (e) => {
29
- e.preventDefault(); // 기본 drag/select 동작 제거
26
+ e.preventDefault();
30
27
  e.stopPropagation();
31
28
 
32
29
  const splitterRect = this.getBoundingClientRect();
33
30
  const isHorizontal = this.#mode === "h";
34
31
 
35
- // 클릭 지점에서 스플리터 경계까지의 오프셋 (이것은 dragBar 초기 위치와는 별개로, 최종 패널 사이즈 계산에 사용됨)
32
+ // 클릭 지점에서 스플리터 경계까지의 오프셋
33
+ // 이 값은 최종 패널 사이즈 계산에 사용되며, 드래그 바 초기 위치와는 직접 관련 없음
36
34
  const clickOffset = isHorizontal
37
35
  ? e.clientX - splitterRect.left
38
36
  : e.clientY - splitterRect.top;
@@ -60,15 +58,14 @@ class nxSplitter extends HTMLElement {
60
58
  return;
61
59
  }
62
60
 
63
- // dragBar를 먼저 DOM에 추가하여 offsetParent를 확보합니다.
61
+ // dragBar를 먼저 DOM에 추가하여 offsetParent를 확보
64
62
  (parent.shadowRoot || parent).appendChild(dragBar);
65
63
 
66
- // dragBar의 실제 offsetParent (position: absolute의 기준이 되는 요소)
67
64
  const dragBarOffsetParent = dragBar.offsetParent;
68
65
 
69
66
  if (!dragBarOffsetParent) {
70
67
  console.error("dragBar's offsetParent could not be determined. Ensure parent or an ancestor has a position property (e.g., relative).");
71
- dragBar.remove(); // 실패 시 dragBar 제거
68
+ dragBar.remove();
72
69
  return;
73
70
  }
74
71
 
@@ -76,7 +73,6 @@ class nxSplitter extends HTMLElement {
76
73
  const prevRect = prev.getBoundingClientRect(); // 뷰포트 기준
77
74
  const nextRect = next.getBoundingClientRect(); // 뷰포트 기준
78
75
 
79
-
80
76
  // 뷰포트 기준 클릭 위치를 dragBarOffsetParent 기준으로 변환하여 초기 dragBar 위치 설정
81
77
  let initialPosInOffsetParent;
82
78
  if (isHorizontal) {
@@ -104,12 +100,10 @@ class nxSplitter extends HTMLElement {
104
100
 
105
101
  const onMove = moveEvent => {
106
102
  const clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;
107
- // 뷰포트 기준 클릭 위치를 offsetParent 기준으로 변환
108
103
  const currentPosInOffsetParent = isHorizontal
109
104
  ? clientPos - dragBarOffsetParentRect.left
110
105
  : clientPos - dragBarOffsetParentRect.top;
111
106
 
112
- // 드래그 바가 최소/최대 범위 내에 있도록 클램프
113
107
  const clampedPos = Math.max(minLimit, Math.min(currentPosInOffsetParent, maxLimit));
114
108
 
115
109
  if (isHorizontal) {
@@ -117,8 +111,6 @@ class nxSplitter extends HTMLElement {
117
111
  } else {
118
112
  dragBar.style.top = `${clampedPos}px`;
119
113
  }
120
-
121
- console.log(clampedPos);
122
114
  };
123
115
 
124
116
  const onUp = (upEvent) => {
@@ -126,34 +118,187 @@ class nxSplitter extends HTMLElement {
126
118
  window.removeEventListener("mouseup", onUp);
127
119
  dragBar.remove();
128
120
 
129
- // 최종 드래그 바의 위치를 offsetParent 기준으로 가져옴
130
121
  const finalDragBarPosInOffsetParent = isHorizontal
131
122
  ? parseFloat(dragBar.style.left)
132
123
  : parseFloat(dragBar.style.top);
133
124
 
134
- // 이전 요소의 새로운 크기 (offsetParent의 시작점부터 드래그 바까지)
135
- const newPrevSize = finalDragBarPosInOffsetParent;
125
+ // ⭐⭐ prev와 next의 padding을 고려한 최종 사이즈 계산 ⭐⭐
126
+ const prevComputedStyle = getComputedStyle(prev);
127
+ const nextComputedStyle = getComputedStyle(next);
128
+
129
+ let prevPaddingStart = 0; // padding-left 또는 padding-top
130
+ let nextPaddingEnd = 0; // padding-right 또는 padding-bottom
136
131
 
137
- // 다음 요소의 새로운 크기 (offsetParent의 전체 크기에서 이전 요소 크기를 뺀 값)
138
- const offsetParentTotalSize = isHorizontal
139
- ? dragBarOffsetParentRect.width
140
- : dragBarOffsetParentRect.height;
141
- const newNextSize = offsetParentTotalSize - newPrevSize;
132
+ if (isHorizontal) {
133
+ prevPaddingStart = parseFloat(prevComputedStyle.paddingLeft) || 0;
134
+ nextPaddingEnd = parseFloat(nextComputedStyle.paddingRight) || 0;
135
+ } else {
136
+ prevPaddingStart = parseFloat(prevComputedStyle.paddingTop) || 0;
137
+ nextPaddingEnd = parseFloat(nextComputedStyle.paddingBottom) || 0;
138
+ }
139
+
140
+ // prev의 새로운 크기: dragBar의 위치 (offsetParent 기준) - prev의 padding-left/top
141
+ // (prev의 content 시작점까지)
142
+ let newPrevInnerSize = finalDragBarPosInOffsetParent - (prevRect[isHorizontal ? 'left' : 'top'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
143
+ newPrevInnerSize -= prevPaddingStart; // prev의 padding-left/top을 제외
144
+
145
+ // next의 새로운 크기: (offsetParent 전체 크기 - dragBar 위치) - next의 padding-right/bottom
146
+ let newNextInnerSize = (dragBarOffsetParentRect[isHorizontal ? 'width' : 'height'] - finalDragBarPosInOffsetParent);
147
+ newNextInnerSize -= nextPaddingEnd; // next의 padding-right/bottom을 제외
148
+
149
+ // 최종 패널 크기에 MIN_PANEL_SIZE 적용 (padding이 적용된 후의 최소 크기)
150
+ const MIN_PANEL_SIZE = 1;
151
+
152
+ // `box-sizing`에 따라 `width`/`height` 설정 방식이 달라짐.
153
+ // 대부분 `border-box`를 사용하므로, `width`를 설정하면 `padding`이 포함됨.
154
+ // 따라서 `newPrevInnerSize`와 `newNextInnerSize`는 `padding`을 제외한 `content` 크기가 아니라
155
+ // 최종적으로 `width`/`height`에 적용될 값이어야 함.
156
+ // 즉, `padding`이 포함된 전체 `width`/`height`로 계산해야 함.
157
+
158
+ // 다시 생각해보면, finalDragBarPosInOffsetParent가 바로 prev의 새로운 width/height가 되어야 합니다.
159
+ // 왜냐하면 dragBar의 위치가 prev의 끝이기 때문입니다.
160
+ // 문제는 prev/next에 padding이 있을 때 이 크기를 어떻게 `style.width`/`height`에 반영할지입니다.
161
+
162
+ // 가장 일반적인 시나리오: flex-grow 사용 (flex 컨테이너에서 권장)
163
+ // `prev`와 `next`에 `flex-grow`를 설정하고 `flex-basis: 0;` (혹은 `auto`)를 사용하면,
164
+ // `flex-grow` 비율로 공간을 나눕니다.
165
+ // 드래그는 이 `flex-grow` 비율을 조정하는 방식으로 구현하는 것이 가장 깔끔합니다.
166
+
167
+ // 현재 prev.style.flex = "none"; next.style.flex = "none"; 방식으로 직접 width/height를 조절하고 있으므로
168
+ // 이 방식에 맞춰 padding을 고려합니다.
169
+ // 즉, finalDragBarPosInOffsetParent는 offsetParent의 왼쪽/위쪽 경계부터 dragBar까지의 거리
170
+ // 이는 곧 prev 요소의 새로운 overall (width/height)가 됩니다.
171
+
172
+ // 여기서 오차가 난다면, `prev`와 `next`의 `box-sizing`이 무엇인지 확인해야 합니다.
173
+ // 만약 `box-sizing: content-box;`라면 `width = content + padding + border`.
174
+ // 만약 `box-sizing: border-box;`라면 `width = content`.
175
+ // 일반적으로 CSS Reset이나 프레임워크는 `border-box`를 사용하므로, 이 가정을 따릅니다.
176
+
177
+ // `border-box` 가정 시: finalDragBarPosInOffsetParent가 `prev`의 새로운 `width`가 됩니다.
178
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 `next`의 새로운 `width`가 됩니다.
179
+ // `padding`은 이 `width` 안에 포함됩니다.
180
+ // 따라서 별도로 `padding` 값을 빼거나 더할 필요가 없습니다.
181
+ // 만약 오차가 있다면, `prev` 또는 `next`에 `margin`이 적용되어 있거나,
182
+ // `parent`에 `gap` 속성 등이 적용되어 있는 것은 아닌지 확인해봐야 합니다.
183
+
184
+ // 하지만 사용자께서 padding에서 오차가 난다고 하셨으므로,
185
+ // `prev`/`next`의 `padding`이 `width`/`height` 계산에 영향을 주는 경우를 상정합니다.
186
+ // 이 경우 `box-sizing: content-box;` 이거나,
187
+ // `width`/`height`를 `content` 크기로 설정하고 싶을 때 발생합니다.
188
+
189
+ // **새로운 delta 계산 (prev의 최종 너비)**
190
+ // dragBar의 최종 위치가 offsetParent 기준.
191
+ // prev.getBoundingClientRect().left - dragBarOffsetParentRect.left : prev의 offsetParent 기준 왼쪽 시작점
192
+ // clickOffset: 마우스 클릭 지점과 스플리터 바 왼쪽 경계의 차이.
193
+ // 이 값은 드래그 바의 '컨텐츠' 시작점을 기준으로 한 오프셋으로 간주.
194
+
195
+ // 가장 간단한 해결책은 `getBoundingClientRect()`로 얻은 `prevRect.width`와 `nextRect.width`의 합을
196
+ // `totalSize`로 사용하는 것이 아니라, `parent`의 실제 사용 가능한 공간을 기준으로 삼고,
197
+ // 드래그 된 `dragBar`의 위치가 해당 공간의 몇 퍼센트를 차지하는지로 `prev`와 `next`의 새로운 `flex-grow`
198
+ // 비율을 계산하는 것입니다.
199
+
200
+ // 현재처럼 직접 width/height를 조절하는 방식에서는
201
+ // `finalDragBarPosInOffsetParent`가 prev의 새로운 `width`가 되는 것이 맞고,
202
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 next의 새로운 `width`가 되는 것이 맞습니다.
203
+ // 만약 padding 때문에 오차가 있다면, 이는 `box-sizing`의 문제이거나,
204
+ // `getBoundingClientRect()`가 `margin`을 포함하지 않는다는 점 때문일 수 있습니다.
205
+
206
+ // **다시 한번 문제의 핵심을 짚어봅시다.**
207
+ // "dragBar가 그만큼 왼쪽으로 그려져 padding 지우면 정상이야."
208
+ // 이 문제는 **드래그 바의 초기 위치 문제**입니다. 이 부분은 이미 `dragBar.offsetParent`를 사용하여 해결했습니다.
209
+
210
+ // "prev, next가 padding 을 가졌을때는 오차가 있어."
211
+ // 이 문제는 **최종 `width`/`height`를 `prev`와 `next`에 적용할 때의 오차**입니다.
212
+ // 즉, `finalPrevSize`와 `finalNextSize`를 계산하는 방식이 문제가 됩니다.
213
+
214
+ // `finalDragBarPosInOffsetParent`는 `offsetParent`의 왼쪽/상단 끝에서 `dragBar`까지의 거리입니다.
215
+ // 이 값이 `prev`의 새로운 너비/높이가 되어야 합니다.
216
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 `next`의 새로운 너비/높이가 되어야 합니다.
217
+
218
+ // 만약 `prev`/`next`가 `padding`을 가질 때 오차가 발생한다면,
219
+ // 이는 `prev.style.width = \`${finalPrevSize}px\`;`를 적용할 때,
220
+ // `finalPrevSize`가 `prev`의 `content + padding + border`를 포함하는 `box-sizing: border-box;`일 경우의 크기여야 하는데,
221
+ // 실제 `prev` 요소의 `box-sizing`이 `content-box`인 경우 `padding`만큼 더 커지기 때문일 수 있습니다.
222
+
223
+ // CSS에서 `box-sizing: border-box;`를 모든 요소에 적용하는 것을 강력히 권장합니다.
224
+ // 예: `* { box-sizing: border-box; }`
225
+
226
+ // 만약 `border-box`를 이미 사용하고 있고 여전히 오차가 있다면,
227
+ // `dragBar`의 `width` (수평 스플리터의 경우) 또는 `height` (수직 스플리터의 경우)를 고려해야 합니다.
228
+ // 스플리터 자체의 두께만큼 `prev`와 `next` 사이의 공간이 발생하기 때문입니다.
229
+
230
+ const splitterThickness = isHorizontal ? splitterRect.width : splitterRect.height; // 스플리터 바의 두께
231
+
232
+ // prev의 새로운 크기: dragBar 위치 - (스플리터 두께의 절반)
233
+ let newPrevWidth = finalDragBarPosInOffsetParent - (splitterThickness / 2);
234
+ // next의 새로운 크기: (offsetParent 전체 크기 - dragBar 위치) - (스플리터 두께의 절반)
235
+ let newNextWidth = offsetParentTotalSize - finalDragBarPosInOffsetParent - (splitterThickness / 2);
236
+
237
+ // 스플리터 두께만큼 중앙에서 나누어주는 로직
238
+ // prev의 끝점은 dragBar의 중앙이 되어야 함
239
+ // 즉, finalDragBarPosInOffsetParent는 dragBar의 좌측 끝점.
240
+ // prev의 새로운 크기는 이 dragBar 좌측 끝점에서 prev의 시작점까지의 거리.
241
+ // 근데 prev의 실제 content box 끝은 dragBar의 중앙까지 와야 한다면,
242
+ // prev의 끝점에서 dragBar 중앙까지의 거리를 계산.
243
+
244
+ // 다시, 드래그 위치 `relative`가 `parent` 기준 스플리터 바의 왼쪽/상단 경계라면
245
+ // `prev`의 새로운 크기는 이 `relative` 값과 동일해야 합니다.
246
+ // 그리고 `next`의 새로운 크기는 `parentTotalSize - relative - splitterThickness`가 되어야 합니다.
247
+ // 여기서 `relative`는 `onMove`에서 계산된 `dragBar.style.left` 또는 `top` 값입니다.
248
+ // `finalDragBarPosInOffsetParent`는 `relative`와 같은 의미.
249
+
250
+ // ⭐ `totalSize` (두 패널의 합계) 대신 `parent`의 사용 가능한 전체 공간을 기준으로
251
+ // `finalPrevSize`와 `finalNextSize`를 다시 계산합니다.
252
+ // 이 방식이 `padding`이나 `margin` 같은 외부 요소에 덜 민감합니다.
253
+
254
+ // `prev.style.width = Xpx`는 prev의 `content + padding + border`가 Xpx가 된다는 가정 (border-box)
255
+ // `prev`의 시작점 (offsetParent 기준)
256
+ const prevStartPosInOffsetParent = isHorizontal
257
+ ? prevRect.left - dragBarOffsetParentRect.left
258
+ : prevRect.top - dragBarOffsetParentRect.top;
259
+
260
+ // `prev`의 새로운 크기 (스플리터 바의 위치까지)
261
+ finalPrevSize = finalDragBarPosInOffsetParent - prevStartPosInOffsetParent;
262
+ // `next`의 새로운 크기 (스플리터 바 이후부터 `offsetParent` 끝까지)
263
+ // `offsetParentTotalSize`는 `offsetParent`의 전체 너비/높이
264
+ finalNextSize = offsetParentTotalSize - (finalDragBarPosInOffsetParent + splitterThickness) + (prevStartPosInOffsetParent + finalPrevSize - nextRect[isHorizontal ? 'left' : 'top'] + dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
265
+ // 이 복잡한 계산은 prev와 next 사이의 간극 (스플리터 두께)을 정확히 반영하기 위함입니다.
266
+ // `finalPrevSize + finalNextSize + splitterThickness`가 `offsetParentTotalSize`와 일치해야 합니다.
267
+
268
+ // ⭐ 최종적으로 계산된 크기:
269
+ // `finalDragBarPosInOffsetParent`는 `offsetParent`의 시작점에서 `dragBar`의 시작점까지의 거리.
270
+ // `prev`의 새 너비는 `finalDragBarPosInOffsetParent` 그 자체가 아니라,
271
+ // `dragBar`가 위치한 곳까지의 `prev`의 너비여야 합니다.
272
+ // 즉, `finalDragBarPosInOffsetParent`는 `prev`의 끝점이 되는 위치.
273
+
274
+ // 다시 한번, `finalDragBarPosInOffsetParent`는 `offsetParent`의 0 지점에서 `dragBar`의 0 지점까지의 거리입니다.
275
+ // `prev` 요소의 최종 너비는 이 `finalDragBarPosInOffsetParent`에서
276
+ // `prev` 요소의 `offsetParent` 기준 시작 지점 (`prevRect.left - dragBarOffsetParentRect.left`)을 뺀 값입니다.
277
+ // 즉, `prev`의 새로운 너비 = `dragBar`의 왼쪽 위치 - `prev`의 왼쪽 위치
278
+
279
+ // 그리고 `next`의 새로운 너비 = `next`의 오른쪽 위치 - `dragBar`의 오른쪽 위치
280
+
281
+ const newPrevWidthCalculated = finalDragBarPosInOffsetParent - (prevRect[isHorizontal ? 'left' : 'top'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
282
+ const newNextWidthCalculated = (nextRect[isHorizontal ? 'right' : 'bottom'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']) - (finalDragBarPosInOffsetParent + splitterThickness);
283
+
284
+
285
+ // 최소 크기 제약
286
+ const MIN_PANEL_SIZE_PX = 1; // 1px 미만으로 작아지지 않도록
287
+ finalPrevSize = Math.max(MIN_PANEL_SIZE_PX, newPrevWidthCalculated);
288
+ finalNextSize = Math.max(MIN_PANEL_SIZE_PX, newNextWidthCalculated);
289
+
290
+ // 만약 `prev + next + splitter`의 합이 부모의 `content` 사이즈와 일치해야 한다면
291
+ // `finalNextSize`를 `offsetParentTotalSize - finalPrevSize - splitterThickness`로 계산하는 것이 더 정확할 수 있습니다.
292
+ // 이렇게 하면 오차가 마지막 패널에 몰아지지만, 합은 정확하게 유지됩니다.
293
+ finalNextSize = Math.max(MIN_PANEL_SIZE_PX, offsetParentTotalSize - finalPrevSize - splitterThickness);
142
294
 
143
- const MIN_PANEL_SIZE = 1; // 패널 최소 크기
144
- let finalPrevSize = Math.max(MIN_PANEL_SIZE, newPrevSize);
145
- let finalNextSize = Math.max(MIN_PANEL_SIZE, newNextSize);
146
295
 
147
- // 기존 flex 값을 저장하고 복원
148
296
  const originalPrevFlex = prev.style.flex;
149
297
  const originalNextFlex = next.style.flex;
150
298
 
151
- // 드래그 중에는 flex를 "none"으로 설정하여 직접 크기 조절
152
299
  prev.style.flex = "none";
153
300
  next.style.flex = "none";
154
301
 
155
- console.log(finalPrevSize, finalNextSize);
156
-
157
302
  if (isHorizontal) {
158
303
  prev.style.width = `${finalPrevSize}px`;
159
304
  next.style.width = `${finalNextSize}px`;
@@ -162,9 +307,6 @@ class nxSplitter extends HTMLElement {
162
307
  next.style.height = `${finalNextSize}px`;
163
308
  }
164
309
 
165
- // 작업 완료 후 원래 flex 값으로 복원
166
- // 주의: width/height가 설정된 상태에서 flex를 복원하면 충돌할 수 있음.
167
- // flex-basis나 flex-grow/shrink를 적절히 조절하는 것이 더 견고한 방법.
168
310
  prev.style.flex = originalPrevFlex;
169
311
  next.style.flex = originalNextFlex;
170
312
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ninegrid2",
3
3
  "type": "module",
4
- "version": "6.862.0",
4
+ "version": "6.863.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -22,17 +22,15 @@ class nxSplitter extends HTMLElement {
22
22
  this.#mode = (!prevRect || !nextRect) || (Math.abs(prevRect.top - nextRect.top) < 5) ? "h" : "v";
23
23
  };
24
24
 
25
- // 이전 #startDrag_BAK 함수는 삭제하거나 주석 처리합니다.
26
- // #startDrag_BAK = (...) => { ... }
27
-
28
25
  #startDrag = (e) => {
29
- e.preventDefault(); // 기본 drag/select 동작 제거
26
+ e.preventDefault();
30
27
  e.stopPropagation();
31
28
 
32
29
  const splitterRect = this.getBoundingClientRect();
33
30
  const isHorizontal = this.#mode === "h";
34
31
 
35
- // 클릭 지점에서 스플리터 경계까지의 오프셋 (이것은 dragBar 초기 위치와는 별개로, 최종 패널 사이즈 계산에 사용됨)
32
+ // 클릭 지점에서 스플리터 경계까지의 오프셋
33
+ // 이 값은 최종 패널 사이즈 계산에 사용되며, 드래그 바 초기 위치와는 직접 관련 없음
36
34
  const clickOffset = isHorizontal
37
35
  ? e.clientX - splitterRect.left
38
36
  : e.clientY - splitterRect.top;
@@ -60,15 +58,14 @@ class nxSplitter extends HTMLElement {
60
58
  return;
61
59
  }
62
60
 
63
- // dragBar를 먼저 DOM에 추가하여 offsetParent를 확보합니다.
61
+ // dragBar를 먼저 DOM에 추가하여 offsetParent를 확보
64
62
  (parent.shadowRoot || parent).appendChild(dragBar);
65
63
 
66
- // dragBar의 실제 offsetParent (position: absolute의 기준이 되는 요소)
67
64
  const dragBarOffsetParent = dragBar.offsetParent;
68
65
 
69
66
  if (!dragBarOffsetParent) {
70
67
  console.error("dragBar's offsetParent could not be determined. Ensure parent or an ancestor has a position property (e.g., relative).");
71
- dragBar.remove(); // 실패 시 dragBar 제거
68
+ dragBar.remove();
72
69
  return;
73
70
  }
74
71
 
@@ -76,7 +73,6 @@ class nxSplitter extends HTMLElement {
76
73
  const prevRect = prev.getBoundingClientRect(); // 뷰포트 기준
77
74
  const nextRect = next.getBoundingClientRect(); // 뷰포트 기준
78
75
 
79
-
80
76
  // 뷰포트 기준 클릭 위치를 dragBarOffsetParent 기준으로 변환하여 초기 dragBar 위치 설정
81
77
  let initialPosInOffsetParent;
82
78
  if (isHorizontal) {
@@ -104,12 +100,10 @@ class nxSplitter extends HTMLElement {
104
100
 
105
101
  const onMove = moveEvent => {
106
102
  const clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;
107
- // 뷰포트 기준 클릭 위치를 offsetParent 기준으로 변환
108
103
  const currentPosInOffsetParent = isHorizontal
109
104
  ? clientPos - dragBarOffsetParentRect.left
110
105
  : clientPos - dragBarOffsetParentRect.top;
111
106
 
112
- // 드래그 바가 최소/최대 범위 내에 있도록 클램프
113
107
  const clampedPos = Math.max(minLimit, Math.min(currentPosInOffsetParent, maxLimit));
114
108
 
115
109
  if (isHorizontal) {
@@ -117,8 +111,6 @@ class nxSplitter extends HTMLElement {
117
111
  } else {
118
112
  dragBar.style.top = `${clampedPos}px`;
119
113
  }
120
-
121
- console.log(clampedPos);
122
114
  };
123
115
 
124
116
  const onUp = (upEvent) => {
@@ -126,34 +118,187 @@ class nxSplitter extends HTMLElement {
126
118
  window.removeEventListener("mouseup", onUp);
127
119
  dragBar.remove();
128
120
 
129
- // 최종 드래그 바의 위치를 offsetParent 기준으로 가져옴
130
121
  const finalDragBarPosInOffsetParent = isHorizontal
131
122
  ? parseFloat(dragBar.style.left)
132
123
  : parseFloat(dragBar.style.top);
133
124
 
134
- // 이전 요소의 새로운 크기 (offsetParent의 시작점부터 드래그 바까지)
135
- const newPrevSize = finalDragBarPosInOffsetParent;
125
+ // ⭐⭐ prev와 next의 padding을 고려한 최종 사이즈 계산 ⭐⭐
126
+ const prevComputedStyle = getComputedStyle(prev);
127
+ const nextComputedStyle = getComputedStyle(next);
128
+
129
+ let prevPaddingStart = 0; // padding-left 또는 padding-top
130
+ let nextPaddingEnd = 0; // padding-right 또는 padding-bottom
136
131
 
137
- // 다음 요소의 새로운 크기 (offsetParent의 전체 크기에서 이전 요소 크기를 뺀 값)
138
- const offsetParentTotalSize = isHorizontal
139
- ? dragBarOffsetParentRect.width
140
- : dragBarOffsetParentRect.height;
141
- const newNextSize = offsetParentTotalSize - newPrevSize;
132
+ if (isHorizontal) {
133
+ prevPaddingStart = parseFloat(prevComputedStyle.paddingLeft) || 0;
134
+ nextPaddingEnd = parseFloat(nextComputedStyle.paddingRight) || 0;
135
+ } else {
136
+ prevPaddingStart = parseFloat(prevComputedStyle.paddingTop) || 0;
137
+ nextPaddingEnd = parseFloat(nextComputedStyle.paddingBottom) || 0;
138
+ }
139
+
140
+ // prev의 새로운 크기: dragBar의 위치 (offsetParent 기준) - prev의 padding-left/top
141
+ // (prev의 content 시작점까지)
142
+ let newPrevInnerSize = finalDragBarPosInOffsetParent - (prevRect[isHorizontal ? 'left' : 'top'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
143
+ newPrevInnerSize -= prevPaddingStart; // prev의 padding-left/top을 제외
144
+
145
+ // next의 새로운 크기: (offsetParent 전체 크기 - dragBar 위치) - next의 padding-right/bottom
146
+ let newNextInnerSize = (dragBarOffsetParentRect[isHorizontal ? 'width' : 'height'] - finalDragBarPosInOffsetParent);
147
+ newNextInnerSize -= nextPaddingEnd; // next의 padding-right/bottom을 제외
148
+
149
+ // 최종 패널 크기에 MIN_PANEL_SIZE 적용 (padding이 적용된 후의 최소 크기)
150
+ const MIN_PANEL_SIZE = 1;
151
+
152
+ // `box-sizing`에 따라 `width`/`height` 설정 방식이 달라짐.
153
+ // 대부분 `border-box`를 사용하므로, `width`를 설정하면 `padding`이 포함됨.
154
+ // 따라서 `newPrevInnerSize`와 `newNextInnerSize`는 `padding`을 제외한 `content` 크기가 아니라
155
+ // 최종적으로 `width`/`height`에 적용될 값이어야 함.
156
+ // 즉, `padding`이 포함된 전체 `width`/`height`로 계산해야 함.
157
+
158
+ // 다시 생각해보면, finalDragBarPosInOffsetParent가 바로 prev의 새로운 width/height가 되어야 합니다.
159
+ // 왜냐하면 dragBar의 위치가 prev의 끝이기 때문입니다.
160
+ // 문제는 prev/next에 padding이 있을 때 이 크기를 어떻게 `style.width`/`height`에 반영할지입니다.
161
+
162
+ // 가장 일반적인 시나리오: flex-grow 사용 (flex 컨테이너에서 권장)
163
+ // `prev`와 `next`에 `flex-grow`를 설정하고 `flex-basis: 0;` (혹은 `auto`)를 사용하면,
164
+ // `flex-grow` 비율로 공간을 나눕니다.
165
+ // 드래그는 이 `flex-grow` 비율을 조정하는 방식으로 구현하는 것이 가장 깔끔합니다.
166
+
167
+ // 현재 prev.style.flex = "none"; next.style.flex = "none"; 방식으로 직접 width/height를 조절하고 있으므로
168
+ // 이 방식에 맞춰 padding을 고려합니다.
169
+ // 즉, finalDragBarPosInOffsetParent는 offsetParent의 왼쪽/위쪽 경계부터 dragBar까지의 거리
170
+ // 이는 곧 prev 요소의 새로운 overall (width/height)가 됩니다.
171
+
172
+ // 여기서 오차가 난다면, `prev`와 `next`의 `box-sizing`이 무엇인지 확인해야 합니다.
173
+ // 만약 `box-sizing: content-box;`라면 `width = content + padding + border`.
174
+ // 만약 `box-sizing: border-box;`라면 `width = content`.
175
+ // 일반적으로 CSS Reset이나 프레임워크는 `border-box`를 사용하므로, 이 가정을 따릅니다.
176
+
177
+ // `border-box` 가정 시: finalDragBarPosInOffsetParent가 `prev`의 새로운 `width`가 됩니다.
178
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 `next`의 새로운 `width`가 됩니다.
179
+ // `padding`은 이 `width` 안에 포함됩니다.
180
+ // 따라서 별도로 `padding` 값을 빼거나 더할 필요가 없습니다.
181
+ // 만약 오차가 있다면, `prev` 또는 `next`에 `margin`이 적용되어 있거나,
182
+ // `parent`에 `gap` 속성 등이 적용되어 있는 것은 아닌지 확인해봐야 합니다.
183
+
184
+ // 하지만 사용자께서 padding에서 오차가 난다고 하셨으므로,
185
+ // `prev`/`next`의 `padding`이 `width`/`height` 계산에 영향을 주는 경우를 상정합니다.
186
+ // 이 경우 `box-sizing: content-box;` 이거나,
187
+ // `width`/`height`를 `content` 크기로 설정하고 싶을 때 발생합니다.
188
+
189
+ // **새로운 delta 계산 (prev의 최종 너비)**
190
+ // dragBar의 최종 위치가 offsetParent 기준.
191
+ // prev.getBoundingClientRect().left - dragBarOffsetParentRect.left : prev의 offsetParent 기준 왼쪽 시작점
192
+ // clickOffset: 마우스 클릭 지점과 스플리터 바 왼쪽 경계의 차이.
193
+ // 이 값은 드래그 바의 '컨텐츠' 시작점을 기준으로 한 오프셋으로 간주.
194
+
195
+ // 가장 간단한 해결책은 `getBoundingClientRect()`로 얻은 `prevRect.width`와 `nextRect.width`의 합을
196
+ // `totalSize`로 사용하는 것이 아니라, `parent`의 실제 사용 가능한 공간을 기준으로 삼고,
197
+ // 드래그 된 `dragBar`의 위치가 해당 공간의 몇 퍼센트를 차지하는지로 `prev`와 `next`의 새로운 `flex-grow`
198
+ // 비율을 계산하는 것입니다.
199
+
200
+ // 현재처럼 직접 width/height를 조절하는 방식에서는
201
+ // `finalDragBarPosInOffsetParent`가 prev의 새로운 `width`가 되는 것이 맞고,
202
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 next의 새로운 `width`가 되는 것이 맞습니다.
203
+ // 만약 padding 때문에 오차가 있다면, 이는 `box-sizing`의 문제이거나,
204
+ // `getBoundingClientRect()`가 `margin`을 포함하지 않는다는 점 때문일 수 있습니다.
205
+
206
+ // **다시 한번 문제의 핵심을 짚어봅시다.**
207
+ // "dragBar가 그만큼 왼쪽으로 그려져 padding 지우면 정상이야."
208
+ // 이 문제는 **드래그 바의 초기 위치 문제**입니다. 이 부분은 이미 `dragBar.offsetParent`를 사용하여 해결했습니다.
209
+
210
+ // "prev, next가 padding 을 가졌을때는 오차가 있어."
211
+ // 이 문제는 **최종 `width`/`height`를 `prev`와 `next`에 적용할 때의 오차**입니다.
212
+ // 즉, `finalPrevSize`와 `finalNextSize`를 계산하는 방식이 문제가 됩니다.
213
+
214
+ // `finalDragBarPosInOffsetParent`는 `offsetParent`의 왼쪽/상단 끝에서 `dragBar`까지의 거리입니다.
215
+ // 이 값이 `prev`의 새로운 너비/높이가 되어야 합니다.
216
+ // `offsetParentTotalSize - finalDragBarPosInOffsetParent`가 `next`의 새로운 너비/높이가 되어야 합니다.
217
+
218
+ // 만약 `prev`/`next`가 `padding`을 가질 때 오차가 발생한다면,
219
+ // 이는 `prev.style.width = \`${finalPrevSize}px\`;`를 적용할 때,
220
+ // `finalPrevSize`가 `prev`의 `content + padding + border`를 포함하는 `box-sizing: border-box;`일 경우의 크기여야 하는데,
221
+ // 실제 `prev` 요소의 `box-sizing`이 `content-box`인 경우 `padding`만큼 더 커지기 때문일 수 있습니다.
222
+
223
+ // CSS에서 `box-sizing: border-box;`를 모든 요소에 적용하는 것을 강력히 권장합니다.
224
+ // 예: `* { box-sizing: border-box; }`
225
+
226
+ // 만약 `border-box`를 이미 사용하고 있고 여전히 오차가 있다면,
227
+ // `dragBar`의 `width` (수평 스플리터의 경우) 또는 `height` (수직 스플리터의 경우)를 고려해야 합니다.
228
+ // 스플리터 자체의 두께만큼 `prev`와 `next` 사이의 공간이 발생하기 때문입니다.
229
+
230
+ const splitterThickness = isHorizontal ? splitterRect.width : splitterRect.height; // 스플리터 바의 두께
231
+
232
+ // prev의 새로운 크기: dragBar 위치 - (스플리터 두께의 절반)
233
+ let newPrevWidth = finalDragBarPosInOffsetParent - (splitterThickness / 2);
234
+ // next의 새로운 크기: (offsetParent 전체 크기 - dragBar 위치) - (스플리터 두께의 절반)
235
+ let newNextWidth = offsetParentTotalSize - finalDragBarPosInOffsetParent - (splitterThickness / 2);
236
+
237
+ // 스플리터 두께만큼 중앙에서 나누어주는 로직
238
+ // prev의 끝점은 dragBar의 중앙이 되어야 함
239
+ // 즉, finalDragBarPosInOffsetParent는 dragBar의 좌측 끝점.
240
+ // prev의 새로운 크기는 이 dragBar 좌측 끝점에서 prev의 시작점까지의 거리.
241
+ // 근데 prev의 실제 content box 끝은 dragBar의 중앙까지 와야 한다면,
242
+ // prev의 끝점에서 dragBar 중앙까지의 거리를 계산.
243
+
244
+ // 다시, 드래그 위치 `relative`가 `parent` 기준 스플리터 바의 왼쪽/상단 경계라면
245
+ // `prev`의 새로운 크기는 이 `relative` 값과 동일해야 합니다.
246
+ // 그리고 `next`의 새로운 크기는 `parentTotalSize - relative - splitterThickness`가 되어야 합니다.
247
+ // 여기서 `relative`는 `onMove`에서 계산된 `dragBar.style.left` 또는 `top` 값입니다.
248
+ // `finalDragBarPosInOffsetParent`는 `relative`와 같은 의미.
249
+
250
+ // ⭐ `totalSize` (두 패널의 합계) 대신 `parent`의 사용 가능한 전체 공간을 기준으로
251
+ // `finalPrevSize`와 `finalNextSize`를 다시 계산합니다.
252
+ // 이 방식이 `padding`이나 `margin` 같은 외부 요소에 덜 민감합니다.
253
+
254
+ // `prev.style.width = Xpx`는 prev의 `content + padding + border`가 Xpx가 된다는 가정 (border-box)
255
+ // `prev`의 시작점 (offsetParent 기준)
256
+ const prevStartPosInOffsetParent = isHorizontal
257
+ ? prevRect.left - dragBarOffsetParentRect.left
258
+ : prevRect.top - dragBarOffsetParentRect.top;
259
+
260
+ // `prev`의 새로운 크기 (스플리터 바의 위치까지)
261
+ finalPrevSize = finalDragBarPosInOffsetParent - prevStartPosInOffsetParent;
262
+ // `next`의 새로운 크기 (스플리터 바 이후부터 `offsetParent` 끝까지)
263
+ // `offsetParentTotalSize`는 `offsetParent`의 전체 너비/높이
264
+ finalNextSize = offsetParentTotalSize - (finalDragBarPosInOffsetParent + splitterThickness) + (prevStartPosInOffsetParent + finalPrevSize - nextRect[isHorizontal ? 'left' : 'top'] + dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
265
+ // 이 복잡한 계산은 prev와 next 사이의 간극 (스플리터 두께)을 정확히 반영하기 위함입니다.
266
+ // `finalPrevSize + finalNextSize + splitterThickness`가 `offsetParentTotalSize`와 일치해야 합니다.
267
+
268
+ // ⭐ 최종적으로 계산된 크기:
269
+ // `finalDragBarPosInOffsetParent`는 `offsetParent`의 시작점에서 `dragBar`의 시작점까지의 거리.
270
+ // `prev`의 새 너비는 `finalDragBarPosInOffsetParent` 그 자체가 아니라,
271
+ // `dragBar`가 위치한 곳까지의 `prev`의 너비여야 합니다.
272
+ // 즉, `finalDragBarPosInOffsetParent`는 `prev`의 끝점이 되는 위치.
273
+
274
+ // 다시 한번, `finalDragBarPosInOffsetParent`는 `offsetParent`의 0 지점에서 `dragBar`의 0 지점까지의 거리입니다.
275
+ // `prev` 요소의 최종 너비는 이 `finalDragBarPosInOffsetParent`에서
276
+ // `prev` 요소의 `offsetParent` 기준 시작 지점 (`prevRect.left - dragBarOffsetParentRect.left`)을 뺀 값입니다.
277
+ // 즉, `prev`의 새로운 너비 = `dragBar`의 왼쪽 위치 - `prev`의 왼쪽 위치
278
+
279
+ // 그리고 `next`의 새로운 너비 = `next`의 오른쪽 위치 - `dragBar`의 오른쪽 위치
280
+
281
+ const newPrevWidthCalculated = finalDragBarPosInOffsetParent - (prevRect[isHorizontal ? 'left' : 'top'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']);
282
+ const newNextWidthCalculated = (nextRect[isHorizontal ? 'right' : 'bottom'] - dragBarOffsetParentRect[isHorizontal ? 'left' : 'top']) - (finalDragBarPosInOffsetParent + splitterThickness);
283
+
284
+
285
+ // 최소 크기 제약
286
+ const MIN_PANEL_SIZE_PX = 1; // 1px 미만으로 작아지지 않도록
287
+ finalPrevSize = Math.max(MIN_PANEL_SIZE_PX, newPrevWidthCalculated);
288
+ finalNextSize = Math.max(MIN_PANEL_SIZE_PX, newNextWidthCalculated);
289
+
290
+ // 만약 `prev + next + splitter`의 합이 부모의 `content` 사이즈와 일치해야 한다면
291
+ // `finalNextSize`를 `offsetParentTotalSize - finalPrevSize - splitterThickness`로 계산하는 것이 더 정확할 수 있습니다.
292
+ // 이렇게 하면 오차가 마지막 패널에 몰아지지만, 합은 정확하게 유지됩니다.
293
+ finalNextSize = Math.max(MIN_PANEL_SIZE_PX, offsetParentTotalSize - finalPrevSize - splitterThickness);
142
294
 
143
- const MIN_PANEL_SIZE = 1; // 패널 최소 크기
144
- let finalPrevSize = Math.max(MIN_PANEL_SIZE, newPrevSize);
145
- let finalNextSize = Math.max(MIN_PANEL_SIZE, newNextSize);
146
295
 
147
- // 기존 flex 값을 저장하고 복원
148
296
  const originalPrevFlex = prev.style.flex;
149
297
  const originalNextFlex = next.style.flex;
150
298
 
151
- // 드래그 중에는 flex를 "none"으로 설정하여 직접 크기 조절
152
299
  prev.style.flex = "none";
153
300
  next.style.flex = "none";
154
301
 
155
- console.log(finalPrevSize, finalNextSize);
156
-
157
302
  if (isHorizontal) {
158
303
  prev.style.width = `${finalPrevSize}px`;
159
304
  next.style.width = `${finalNextSize}px`;
@@ -162,9 +307,6 @@ class nxSplitter extends HTMLElement {
162
307
  next.style.height = `${finalNextSize}px`;
163
308
  }
164
309
 
165
- // 작업 완료 후 원래 flex 값으로 복원
166
- // 주의: width/height가 설정된 상태에서 flex를 복원하면 충돌할 수 있음.
167
- // flex-basis나 flex-grow/shrink를 적절히 조절하는 것이 더 견고한 방법.
168
310
  prev.style.flex = originalPrevFlex;
169
311
  next.style.flex = originalNextFlex;
170
312
  };