table-minimap 1.0.7 → 1.1.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.
@@ -1,11 +1,12 @@
1
- var H = Object.defineProperty;
2
- var R = (u, t, e) => t in u ? H(u, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : u[t] = e;
3
- var n = (u, t, e) => R(u, typeof t != "symbol" ? t + "" : t, e);
4
- const X = {
1
+ var X = Object.defineProperty;
2
+ var z = (v, t, e) => t in v ? X(v, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : v[t] = e;
3
+ var n = (v, t, e) => z(v, typeof t != "symbol" ? t + "" : t, e);
4
+ const H = {
5
5
  mode: "columns",
6
6
  height: 40,
7
7
  position: "bottom",
8
8
  fixedWidth: 300,
9
+ fixedPosition: "bottom-right",
9
10
  compact: !1,
10
11
  draggable: !0,
11
12
  showViewport: !0,
@@ -31,6 +32,8 @@ class F {
31
32
  n(this, "isCompactMode");
32
33
  /** Whether the compact minimap is currently collapsed */
33
34
  n(this, "isCompactCollapsed", !1);
35
+ /** Whether the compact minimap is currently expanding (transition in progress) */
36
+ n(this, "isCompactExpanding", !1);
34
37
  /** Timeout used to collapse compact mode after pointer leave */
35
38
  n(this, "compactCollapseTimer", null);
36
39
  /** The scrollable container (parent of table) */
@@ -72,9 +75,7 @@ class F {
72
75
  n(this, "panStartX", 0);
73
76
  /** Currently hovered column index (-1 = none) */
74
77
  n(this, "hoveredColumn", -1);
75
- /** Currently focused/clicked column index (-1 = none) */
76
- n(this, "focusedColumn", -1);
77
- /** Drag start position */
78
+ /** Drag start X position */
78
79
  n(this, "dragStartX", 0);
79
80
  /** Drag start scroll position */
80
81
  n(this, "dragStartScrollLeft", 0);
@@ -90,7 +91,7 @@ class F {
90
91
  n(this, "isDestroyed", !1);
91
92
  /** Whether we started a potential pan (waiting to see if it's a click or drag) */
92
93
  n(this, "isPotentialPan", !1);
93
- this.table = this.resolveTable(t), this.options = { ...X, ...e }, this.isCompactMode = this.options.compact && this.options.position === "fixed", this.boundHandlers = {
94
+ this.table = this.resolveTable(t), this.options = { ...H, ...e }, this.isCompactMode = this.options.compact && this.options.position === "fixed", this.boundHandlers = {
94
95
  onScroll: this.onScroll.bind(this),
95
96
  onPointerDown: this.onPointerDown.bind(this),
96
97
  onPointerMove: this.onPointerMove.bind(this),
@@ -170,13 +171,13 @@ class F {
170
171
  }
171
172
  const i = this.table.offsetWidth || 1;
172
173
  Array.from(e).forEach((o) => {
173
- const r = o.colSpan || 1, s = o.offsetWidth;
174
- for (let a = 0; a < r; a++) {
175
- const l = s / r;
174
+ const a = o.colSpan || 1, s = o.offsetWidth;
175
+ for (let l = 0; l < a; l++) {
176
+ const r = s / a;
176
177
  this.columns.push({
177
178
  index: this.columns.length,
178
- width: l,
179
- widthPercent: l / i * 100
179
+ width: r,
180
+ widthPercent: r / i * 100
180
181
  });
181
182
  }
182
183
  }), this.columns.length === 0 && this.columns.push({
@@ -189,15 +190,15 @@ class F {
189
190
  * Creates the minimap DOM element
190
191
  */
191
192
  createMinimapElement() {
192
- this.minimapEl = document.createElement("div"), this.minimapEl.className = `tm-minimap tm-minimap--${this.options.position}`, this.minimapEl.style.setProperty("--tm-minimap-height", `${this.options.height}px`), this.options.position === "fixed" && this.minimapEl.style.setProperty("--tm-minimap-width", `${this.options.fixedWidth}px`), this.isCompactMode ? (this.minimapEl.classList.add("tm-minimap--compact", "tm-minimap--compact-collapsed"), this.minimapEl.style.setProperty("--tm-compact-dot-size", `${A}px`), this.isCompactCollapsed = !0, this.applyCompactDimensions(!0), this.minimapEl.setAttribute("aria-expanded", "false")) : this.minimapEl.setAttribute("aria-expanded", "true"), this.minimapEl.setAttribute("role", "slider"), this.minimapEl.setAttribute("aria-label", "Table minimap navigation"), this.minimapEl.setAttribute("aria-valuemin", "0"), this.minimapEl.setAttribute("aria-valuemax", "100"), this.minimapEl.setAttribute("tabindex", "0"), this.options.mode === "canvas" ? this.createCanvasContent() : this.createColumnsContent(), this.options.showViewport && this.createViewportIndicator(), this.insertMinimap();
193
+ this.minimapEl = document.createElement("div"), this.minimapEl.className = `tm-minimap tm-minimap--${this.options.position}`, this.minimapEl.style.setProperty("--tm-minimap-height", `${this.options.height}px`), this.options.position === "fixed" && (this.minimapEl.style.setProperty("--tm-minimap-width", `${this.options.fixedWidth}px`), this.minimapEl.classList.add(`tm-minimap--${this.options.fixedPosition}`)), this.isCompactMode ? (this.minimapEl.classList.add("tm-minimap--compact", "tm-minimap--compact-collapsed"), this.minimapEl.style.setProperty("--tm-compact-dot-size", `${A}px`), this.isCompactCollapsed = !0, this.applyCompactDimensions(!0), this.minimapEl.setAttribute("aria-expanded", "false")) : this.minimapEl.setAttribute("aria-expanded", "true"), this.minimapEl.setAttribute("role", "slider"), this.minimapEl.setAttribute("aria-label", "Table minimap navigation"), this.minimapEl.setAttribute("aria-valuemin", "0"), this.minimapEl.setAttribute("aria-valuemax", "100"), this.minimapEl.setAttribute("tabindex", "0"), this.options.mode === "canvas" ? this.createCanvasContent() : this.createColumnsContent(), this.options.showViewport && this.createViewportIndicator(), this.insertMinimap();
193
194
  }
194
195
  /**
195
196
  * Creates columns-mode content
196
197
  */
197
198
  createColumnsContent() {
198
- this.minimapEl && (this.columnsEl = document.createElement("div"), this.columnsEl.className = "tm-columns", this.columns.forEach((t) => {
199
- const e = document.createElement("div");
200
- e.className = "tm-column", e.style.width = `${t.widthPercent}%`, this.columnsEl.appendChild(e);
199
+ this.minimapEl && (this.columnsEl = document.createElement("div"), this.columnsEl.className = "tm-columns", this.columns.forEach(() => {
200
+ const t = document.createElement("div");
201
+ t.className = "tm-column", this.columnsEl.appendChild(t);
201
202
  }), this.minimapEl.appendChild(this.columnsEl));
202
203
  }
203
204
  /**
@@ -223,8 +224,8 @@ class F {
223
224
  getComputedStyle(t).position === "static" && (t.style.position = "relative");
224
225
  const i = this.scrollContainer.nextSibling;
225
226
  i ? t.insertBefore(this.minimapEl, i) : t.appendChild(this.minimapEl), this.minimapEl.style.position = "absolute";
226
- const o = this.isCompactMode ? 8 : 12;
227
- this.minimapEl.style.bottom = `${o}px`, this.minimapEl.style.right = `${o}px`, this.minimapEl.style.marginTop = "0";
227
+ const o = this.isCompactMode ? 8 : 12, a = this.options.fixedPosition;
228
+ this.minimapEl.style.top = "", this.minimapEl.style.bottom = "", this.minimapEl.style.left = "", this.minimapEl.style.right = "", this.minimapEl.style.marginTop = "0", a === "top-left" ? (this.minimapEl.style.top = `${o}px`, this.minimapEl.style.left = `${o}px`) : a === "top-right" ? (this.minimapEl.style.top = `${o}px`, this.minimapEl.style.right = `${o}px`) : a === "bottom-left" ? (this.minimapEl.style.bottom = `${o}px`, this.minimapEl.style.left = `${o}px`) : (this.minimapEl.style.bottom = `${o}px`, this.minimapEl.style.right = `${o}px`);
228
229
  }
229
230
  } else if (this.options.position === "top")
230
231
  t ? t.insertBefore(this.minimapEl, this.scrollContainer) : this.scrollContainer.insertBefore(this.minimapEl, this.scrollContainer.firstChild);
@@ -261,25 +262,25 @@ class F {
261
262
  * Canvas metrics for calculations - cached values to avoid repeated computations
262
263
  */
263
264
  getCanvasMetrics() {
264
- var m;
265
- const t = ((m = this.minimapEl) == null ? void 0 : m.offsetWidth) ?? 0, e = this.zoomState.level, i = this.columns.length, o = 1 / e, r = i * o, s = r > 0 ? t / r : 0;
266
- let a = 0;
265
+ var p;
266
+ const t = ((p = this.minimapEl) == null ? void 0 : p.offsetWidth) ?? 0, e = this.zoomState.level, i = this.columns.length, o = 1 / e, a = i * o, s = a > 0 ? t / a : 0;
267
+ let l = 0;
267
268
  if (e > 1 && this.scrollContainer) {
268
- const { scrollLeft: p, scrollWidth: E, clientWidth: g } = this.scrollContainer, c = Math.max(E - g, 1);
269
- a = p / c * (1 - o);
269
+ const { scrollLeft: m, scrollWidth: E, clientWidth: g } = this.scrollContainer, u = Math.max(E - g, 1);
270
+ l = m / u * (1 - o);
270
271
  }
271
- const l = a * i, d = Math.floor(l), v = Math.min(Math.ceil(l + r) + 1, i), f = -(l - d) * s;
272
+ const r = l * i, c = Math.floor(r), h = Math.min(Math.ceil(r + a) + 1, i), f = -(r - c) * s;
272
273
  return {
273
274
  width: t,
274
275
  zoom: e,
275
276
  numCols: i,
276
277
  visibleRatio: o,
277
- visibleCols: r,
278
+ visibleCols: a,
278
279
  cellWidth: s,
279
- panX: a,
280
- startColFloat: l,
281
- startCol: d,
282
- endCol: v,
280
+ panX: l,
281
+ startColFloat: r,
282
+ startCol: c,
283
+ endCol: h,
283
284
  xOffset: f
284
285
  };
285
286
  }
@@ -287,23 +288,19 @@ class F {
287
288
  * Calculates column index from mouse X position
288
289
  */
289
290
  getColumnAtX(t) {
290
- const { width: e, numCols: i, panX: o, visibleRatio: r } = this.getCanvasMetrics();
291
+ const { width: e, numCols: i, panX: o, visibleRatio: a } = this.getCanvasMetrics();
291
292
  if (i === 0 || e === 0) return -1;
292
- const s = t / e, a = o + s * r, l = Math.floor(a * i);
293
- return Math.max(0, Math.min(i - 1, l));
293
+ const s = t / e, l = o + s * a, r = Math.floor(l * i);
294
+ return Math.max(0, Math.min(i - 1, r));
294
295
  }
295
296
  /**
296
297
  * Updates the viewport indicator position and size
297
- * In canvas mode, the viewport shows the focused (clicked) column
298
+ * Shows the visible portion of the table (columns mode only)
298
299
  */
299
300
  updateViewport() {
300
301
  if (!this.viewportEl || !this.minimapEl) return;
301
302
  if (this.options.mode === "canvas") {
302
- if (this.focusedColumn >= 0 && this.columns.length > 0) {
303
- const { cellWidth: r, startColFloat: s } = this.getCanvasMetrics(), a = (this.focusedColumn - s) * r;
304
- this.viewportEl.style.cssText = `width:${r}px;left:${a}px;display:block`;
305
- } else
306
- this.viewportEl.style.display = "none";
303
+ this.viewportEl.style.display = "none";
307
304
  return;
308
305
  }
309
306
  const t = this.minimapEl.offsetWidth, e = Math.max(t * this.scrollState.viewportRatio, 20), o = (t - e) * this.scrollState.positionRatio;
@@ -321,11 +318,11 @@ class F {
321
318
  * Renders the visible portion of the table directly onto the canvas
322
319
  */
323
320
  renderTableDirect(t, e) {
324
- var M, P, L, D;
321
+ var S, y, P, D;
325
322
  if (!this.canvasCtx) return;
326
- const i = this.canvasCtx, { width: o, numCols: r, cellWidth: s, startCol: a, endCol: l, xOffset: d } = t, v = Array.from(this.table.querySelectorAll("tr")), f = v.length;
327
- if (f === 0 || r === 0) return;
328
- const m = Math.min(e * 0.15, 30), p = (e - m) / f, E = Math.min(p * 0.6, s * 0.15, 14), g = Math.min(m * 0.6, s * 0.15, 14), c = {
323
+ const i = this.canvasCtx, { width: o, numCols: a, cellWidth: s, startCol: l, endCol: r, xOffset: c } = t, h = Array.from(this.table.querySelectorAll("tr")), f = h.length;
324
+ if (f === 0 || a === 0) return;
325
+ const p = Math.min(e * 0.15, 30), m = (e - p) / f, E = Math.min(m * 0.6, s * 0.15, 14), g = Math.min(p * 0.6, s * 0.15, 14), u = {
329
326
  bg: "#ffffff",
330
327
  headerBg: "#f1f5f9",
331
328
  border: "#e2e8f0",
@@ -335,35 +332,35 @@ class F {
335
332
  hoverFill: "rgba(59, 130, 246, 0.08)",
336
333
  hoverStroke: "rgba(59, 130, 246, 0.3)"
337
334
  };
338
- i.fillStyle = c.bg, i.fillRect(0, 0, o, e), i.fillStyle = c.headerBg, i.fillRect(0, 0, o, m);
339
- const w = this.table.querySelector("thead tr") || v[0], y = w ? Array.from(w.querySelectorAll("th, td")) : [];
335
+ i.fillStyle = u.bg, i.fillRect(0, 0, o, e), i.fillStyle = u.headerBg, i.fillRect(0, 0, o, p);
336
+ const x = this.table.querySelector("thead tr") || h[0], L = x ? Array.from(x.querySelectorAll("th, td")) : [];
340
337
  i.font = `bold ${g}px system-ui, sans-serif`, i.textBaseline = "middle";
341
- for (let h = a; h < l; h++) {
342
- const C = d + (h - a) * s;
338
+ for (let d = l; d < r; d++) {
339
+ const C = c + (d - l) * s;
343
340
  if (C + s < 0 || C > o) continue;
344
- i.strokeStyle = c.border, i.lineWidth = 1, i.strokeRect(C, 0, s, m);
345
- const b = ((P = (M = y[h]) == null ? void 0 : M.textContent) == null ? void 0 : P.trim()) || `Col ${h + 1}`;
346
- i.fillStyle = c.headerText, i.save(), i.beginPath(), i.rect(C + 2, 0, s - 4, m), i.clip(), i.fillText(b, C + 4, m / 2), i.restore();
341
+ i.strokeStyle = u.border, i.lineWidth = 1, i.strokeRect(C, 0, s, p);
342
+ const b = ((y = (S = L[d]) == null ? void 0 : S.textContent) == null ? void 0 : y.trim()) || `Col ${d + 1}`;
343
+ i.fillStyle = u.headerText, i.save(), i.beginPath(), i.rect(C + 2, 0, s - 4, p), i.clip(), i.fillText(b, C + 4, p / 2), i.restore();
347
344
  }
348
345
  i.font = `${E}px system-ui, sans-serif`;
349
- for (let h = 0; h < v.length; h++) {
350
- const C = v[h];
346
+ for (let d = 0; d < h.length; d++) {
347
+ const C = h[d];
351
348
  if (C.closest("thead")) continue;
352
- const b = m + h * p;
353
- if (b + p < 0 || b > e) continue;
354
- h % 2 === 1 && (i.fillStyle = c.altRow, i.fillRect(0, b, o, p));
355
- const W = Array.from(C.querySelectorAll("th, td"));
356
- for (let S = a; S < l; S++) {
357
- const x = d + (S - a) * s;
358
- if (x + s < 0 || x > o) continue;
359
- i.strokeStyle = c.border, i.lineWidth = 0.5, i.strokeRect(x, b, s, p);
360
- const k = (D = (L = W[S]) == null ? void 0 : L.textContent) == null ? void 0 : D.trim();
361
- k && (i.fillStyle = c.text, i.save(), i.beginPath(), i.rect(x + 2, b, s - 4, p), i.clip(), i.fillText(k, x + 4, b + p / 2), i.restore());
349
+ const b = p + d * m;
350
+ if (b + m < 0 || b > e) continue;
351
+ d % 2 === 1 && (i.fillStyle = u.altRow, i.fillRect(0, b, o, m));
352
+ const R = Array.from(C.querySelectorAll("th, td"));
353
+ for (let M = l; M < r; M++) {
354
+ const w = c + (M - l) * s;
355
+ if (w + s < 0 || w > o) continue;
356
+ i.strokeStyle = u.border, i.lineWidth = 0.5, i.strokeRect(w, b, s, m);
357
+ const k = (D = (P = R[M]) == null ? void 0 : P.textContent) == null ? void 0 : D.trim();
358
+ k && (i.fillStyle = u.text, i.save(), i.beginPath(), i.rect(w + 2, b, s - 4, m), i.clip(), i.fillText(k, w + 4, b + m / 2), i.restore());
362
359
  }
363
360
  }
364
- if (this.hoveredColumn >= a && this.hoveredColumn < l) {
365
- const h = d + (this.hoveredColumn - a) * s;
366
- i.fillStyle = c.hoverFill, i.fillRect(h, 0, s, e), i.strokeStyle = c.hoverStroke, i.lineWidth = 1, i.strokeRect(h, 0, s, e);
361
+ if (this.hoveredColumn >= l && this.hoveredColumn < r) {
362
+ const d = c + (this.hoveredColumn - l) * s;
363
+ i.fillStyle = u.hoverFill, i.fillRect(d, 0, s, e), i.strokeStyle = u.hoverStroke, i.lineWidth = 1, i.strokeRect(d, 0, s, e);
367
364
  }
368
365
  }
369
366
  /**
@@ -393,27 +390,22 @@ class F {
393
390
  t.preventDefault(), this.expandCompact();
394
391
  return;
395
392
  }
396
- if (this.isDragging || this.isPanning || this.wasPanning || t.target === this.viewportEl) return;
397
- const { scrollWidth: e, clientWidth: i } = this.scrollContainer, o = this.columns.length;
398
- if (this.hoveredColumn >= 0 && o > 0) {
399
- this.focusedColumn = this.hoveredColumn;
400
- const E = e / o, c = (this.hoveredColumn + 0.5) * E - i / 2, w = e - i, y = Math.max(0, Math.min(w, c));
401
- this.scrollContainer.scrollTo({
402
- left: y,
403
- behavior: "smooth"
404
- }), this.updateViewport();
393
+ if (this.isCompactExpanding || this.isDragging || this.isPanning || this.wasPanning) return;
394
+ const { scrollWidth: e, clientWidth: i } = this.scrollContainer, o = e - i, a = this.minimapEl.getBoundingClientRect(), s = t.clientX - a.left;
395
+ if (this.options.mode === "canvas") {
396
+ const c = this.getColumnAtX(s);
397
+ if (c >= 0) {
398
+ const h = this.columns.length, f = e / h, m = (c + 0.5) * f - i / 2;
399
+ this.scrollContainer.scrollTo({
400
+ left: Math.max(0, Math.min(o, m)),
401
+ behavior: "smooth"
402
+ });
403
+ }
405
404
  return;
406
405
  }
407
- const r = this.minimapEl.getBoundingClientRect(), a = (t.clientX - r.left) / r.width, l = this.zoomState.level;
408
- let d;
409
- if (l > 1) {
410
- const g = this.scrollContainer.scrollLeft / Math.max(e - i, 1), c = 1 / l;
411
- d = g * (1 - c) + a * c;
412
- } else
413
- d = a;
414
- const f = d * e - i / 2, m = e - i, p = Math.max(0, Math.min(m, f));
406
+ const r = s / a.width * o;
415
407
  this.scrollContainer.scrollTo({
416
- left: p,
408
+ left: Math.max(0, Math.min(o, r)),
417
409
  behavior: "smooth"
418
410
  });
419
411
  }
@@ -433,17 +425,14 @@ class F {
433
425
  onPointerMove(t) {
434
426
  if (this.isPotentialPan && !this.isPanning && this.canvasEl && this.zoomState.level > 1 && Math.abs(t.clientX - this.panStartX) > 3 && (this.isPanning = !0, this.canvasEl.style.cursor = "grabbing"), this.isPanning && this.canvasEl && this.minimapEl && this.scrollContainer) {
435
427
  t.preventDefault();
436
- const a = t.clientX - this.panStartX, l = this.minimapEl.offsetWidth, { scrollWidth: d, clientWidth: v } = this.scrollContainer, f = d - v, m = a / l * f * this.zoomState.level, p = this.dragStartScrollLeft + m;
437
- this.scrollContainer.scrollLeft = Math.max(0, Math.min(f, p)), this.updateScrollState(), this.updateViewport(), this.render();
428
+ const c = t.clientX - this.panStartX, h = this.minimapEl.offsetWidth, { scrollWidth: f, clientWidth: p } = this.scrollContainer, m = f - p, E = c / h * m * this.zoomState.level, g = this.dragStartScrollLeft + E;
429
+ this.scrollContainer.scrollLeft = Math.max(0, Math.min(m, g)), this.updateScrollState(), this.updateViewport(), this.render();
438
430
  return;
439
431
  }
440
432
  if (!this.isDragging || !this.minimapEl || !this.scrollContainer) return;
441
433
  t.preventDefault();
442
- const e = t.clientX - this.dragStartX, i = this.minimapEl.offsetWidth, o = this.scrollContainer.scrollWidth - this.scrollContainer.clientWidth, r = e / i * o, s = this.dragStartScrollLeft + r;
443
- this.scrollContainer.scrollLeft = Math.max(
444
- 0,
445
- Math.min(o, s)
446
- ), this.updateScrollState(), this.updateViewport();
434
+ const { scrollWidth: e, clientWidth: i } = this.scrollContainer, o = this.minimapEl.offsetWidth, a = e - i, l = (t.clientX - this.dragStartX) / o * a, r = this.dragStartScrollLeft + l;
435
+ this.scrollContainer.scrollLeft = Math.max(0, Math.min(a, r)), this.updateScrollState(), this.updateViewport();
447
436
  }
448
437
  /**
449
438
  * Handles pointer up to end drag
@@ -471,19 +460,26 @@ class F {
471
460
  * @param e - Wheel event
472
461
  */
473
462
  onWheel(t) {
474
- if (!this.options.zoomable || this.options.mode !== "canvas") return;
463
+ if (!this.options.zoomable || this.options.mode !== "canvas" || !this.canvasEl || !this.scrollContainer || !this.minimapEl) return;
475
464
  t.preventDefault();
476
- const e = -t.deltaY * this.options.zoomSpeed, i = Math.max(
465
+ const e = this.zoomState.level, i = -t.deltaY * this.options.zoomSpeed, o = Math.max(
477
466
  this.options.minZoom,
478
- Math.min(this.options.maxZoom, this.zoomState.level + e)
467
+ Math.min(this.options.maxZoom, e + i)
479
468
  );
469
+ if (o === e) return;
470
+ const a = this.canvasEl.getBoundingClientRect(), s = t.clientX - a.left, l = this.minimapEl.offsetWidth, r = s / l, c = 1 / e, { scrollLeft: h, scrollWidth: f, clientWidth: p } = this.scrollContainer, m = Math.max(f - p, 1), E = h / m, u = (e > 1 ? E * (1 - c) : 0) + r * c;
480
471
  this.zoomState = {
481
- level: i,
472
+ level: o,
482
473
  panX: 0,
483
- // Not used anymore - derived from scroll position
484
- isMinZoom: i <= this.options.minZoom,
485
- isMaxZoom: i >= this.options.maxZoom
486
- }, this.render();
474
+ isMinZoom: o <= this.options.minZoom,
475
+ isMaxZoom: o >= this.options.maxZoom
476
+ };
477
+ const x = 1 / o;
478
+ if (o > 1) {
479
+ const S = (u - r * x) / (1 - x), y = Math.max(0, Math.min(m, S * m));
480
+ this.scrollContainer.scrollLeft = y;
481
+ }
482
+ this.updateScrollState(), this.render();
487
483
  }
488
484
  /**
489
485
  * Handles pointer down on canvas for drag start (scrolls table when zoomed)
@@ -511,7 +507,9 @@ class F {
511
507
  * Expands the compact minimap and clears any pending collapse.
512
508
  */
513
509
  expandCompact() {
514
- !this.isCompactMode || !this.minimapEl || (this.clearCompactCollapseTimer(), this.applyCompactDimensions(!1), this.render());
510
+ !this.isCompactMode || !this.minimapEl || this.isCompactExpanding || (this.clearCompactCollapseTimer(), this.isCompactExpanding = !0, this.applyCompactDimensions(!1), setTimeout(() => {
511
+ this.isCompactExpanding = !1, !this.isDestroyed && !this.isCompactCollapsed && (this.updateScrollState(), this.render());
512
+ }, 200));
515
513
  }
516
514
  /**
517
515
  * Collapses the compact minimap to the small dot handle.
@@ -597,9 +595,9 @@ class F {
597
595
  */
598
596
  onResize() {
599
597
  this.isDestroyed || (this.rafId !== null && cancelAnimationFrame(this.rafId), this.rafId = requestAnimationFrame(() => {
600
- this.detectColumns(), this.updateScrollState(), this.render(), this.options.mode === "columns" && this.columnsEl && this.minimapEl && (this.columnsEl.innerHTML = "", this.columns.forEach((t) => {
601
- const e = document.createElement("div");
602
- e.className = "tm-column", e.style.width = `${t.widthPercent}%`, this.columnsEl.appendChild(e);
598
+ this.detectColumns(), this.updateScrollState(), this.render(), this.options.mode === "columns" && this.columnsEl && this.minimapEl && (this.columnsEl.innerHTML = "", this.columns.forEach(() => {
599
+ const t = document.createElement("div");
600
+ t.className = "tm-column", this.columnsEl.appendChild(t);
603
601
  })), this.rafId = null;
604
602
  }));
605
603
  }
@@ -607,9 +605,9 @@ class F {
607
605
  * Handles table mutation events
608
606
  */
609
607
  onTableMutation() {
610
- this.isDestroyed || (this.detectColumns(), this.updateScrollState(), this.render(), this.options.mode === "columns" && this.columnsEl && (this.columnsEl.innerHTML = "", this.columns.forEach((t) => {
611
- const e = document.createElement("div");
612
- e.className = "tm-column", e.style.width = `${t.widthPercent}%`, this.columnsEl.appendChild(e);
608
+ this.isDestroyed || (this.detectColumns(), this.updateScrollState(), this.render(), this.options.mode === "columns" && this.columnsEl && (this.columnsEl.innerHTML = "", this.columns.forEach(() => {
609
+ const t = document.createElement("div");
610
+ t.className = "tm-column", this.columnsEl.appendChild(t);
613
611
  })));
614
612
  }
615
613
  /**
@@ -637,7 +635,7 @@ class F {
637
635
  scrollToColumn(t, e = !0) {
638
636
  if (!this.scrollContainer || t < 0 || t >= this.columns.length)
639
637
  return;
640
- const o = this.columns.slice(0, t).reduce((r, s) => r + s.width, 0);
638
+ const o = this.columns.slice(0, t).reduce((a, s) => a + s.width, 0);
641
639
  this.scrollContainer.scrollTo({
642
640
  left: o,
643
641
  behavior: e ? "smooth" : "auto"
@@ -647,9 +645,9 @@ class F {
647
645
  * Forces a refresh of the minimap
648
646
  */
649
647
  refresh() {
650
- this.isDestroyed || (this.scrollContainer = this.findScrollContainer(), this.detectColumns(), this.updateScrollState(), this.render(), this.options.mode === "columns" && this.columnsEl && (this.columnsEl.innerHTML = "", this.columns.forEach((t) => {
651
- const e = document.createElement("div");
652
- e.className = "tm-column", e.style.width = `${t.widthPercent}%`, this.columnsEl.appendChild(e);
648
+ this.isDestroyed || (this.scrollContainer = this.findScrollContainer(), this.detectColumns(), this.updateScrollState(), this.render(), this.options.mode === "columns" && this.columnsEl && (this.columnsEl.innerHTML = "", this.columns.forEach(() => {
649
+ const t = document.createElement("div");
650
+ t.className = "tm-column", this.columnsEl.appendChild(t);
653
651
  })));
654
652
  }
655
653
  /**
@@ -664,21 +662,26 @@ class F {
664
662
  * Sets the zoom level programmatically (canvas mode only)
665
663
  *
666
664
  * @param level - Zoom level (1 = no zoom)
667
- * @param panX - Optional pan position (0-1)
665
+ * @param panX - Optional pan position (0-1), controls which part of table is visible
668
666
  */
669
667
  setZoom(t, e) {
670
- if (this.isDestroyed || this.options.mode !== "canvas") return;
668
+ if (this.isDestroyed || this.options.mode !== "canvas" || !this.scrollContainer) return;
671
669
  const i = Math.max(
672
670
  this.options.minZoom,
673
671
  Math.min(this.options.maxZoom, t)
674
- ), r = 1 - 1 / i;
675
- let s = e !== void 0 ? e : this.zoomState.panX;
676
- s = Math.max(0, Math.min(r, s)), this.zoomState = {
672
+ ), o = 1 / i, a = 1 - o;
673
+ let s = e !== void 0 ? e : 0;
674
+ if (s = Math.max(0, Math.min(a, s)), this.zoomState = {
677
675
  level: i,
678
- panX: i > 1 ? s : 0,
676
+ panX: 0,
677
+ // Not used - panX is derived from scroll position
679
678
  isMinZoom: i <= this.options.minZoom,
680
679
  isMaxZoom: i >= this.options.maxZoom
681
- }, this.render();
680
+ }, i > 1 && s > 0) {
681
+ const { scrollWidth: l, clientWidth: r } = this.scrollContainer, c = Math.max(l - r, 1), h = s / (1 - o);
682
+ this.scrollContainer.scrollLeft = Math.max(0, Math.min(c, h * c));
683
+ } else i <= 1 && (this.scrollContainer.scrollLeft = 0);
684
+ this.updateScrollState(), this.render();
682
685
  }
683
686
  /**
684
687
  * Resets zoom to default (shows full table overview)
@@ -696,8 +699,8 @@ class F {
696
699
  if (this.isDestroyed || this.options.mode !== "canvas") return;
697
700
  const i = this.columns.length;
698
701
  if (i === 0) return;
699
- const o = Math.max(0, Math.min(i - 1, t)), s = Math.max(o + 1, Math.min(i, e)) - o, a = i / s, l = o / i;
700
- this.setZoom(a, l);
702
+ const o = Math.max(0, Math.min(i - 1, t)), s = Math.max(o + 1, Math.min(i, e)) - o, l = i / s, r = o / i;
703
+ this.setZoom(l, r);
701
704
  }
702
705
  /**
703
706
  * Destroys the minimap instance and cleans up resources
@@ -706,12 +709,12 @@ class F {
706
709
  this.isDestroyed || (this.isDestroyed = !0, this.clearCompactCollapseTimer(), this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null), this.scrollContainer && this.scrollContainer.removeEventListener("scroll", this.boundHandlers.onScroll), this.minimapEl && (this.minimapEl.removeEventListener("click", this.boundHandlers.onMinimapClick), this.minimapEl.removeEventListener("focusin", this.boundHandlers.onCompactFocusIn), this.minimapEl.removeEventListener("focusout", this.boundHandlers.onCompactFocusOut), this.minimapEl.removeEventListener("keydown", this.boundHandlers.onCompactKeyDown)), document.removeEventListener("click", this.boundHandlers.onDocumentClick), this.viewportEl && (this.viewportEl.removeEventListener("pointerdown", this.boundHandlers.onPointerDown), this.viewportEl.removeEventListener("wheel", this.boundHandlers.onWheel)), this.canvasEl && (this.canvasEl.removeEventListener("wheel", this.boundHandlers.onWheel), this.canvasEl.removeEventListener("pointerdown", this.boundHandlers.onCanvasPointerDown), this.canvasEl.removeEventListener("mousemove", this.boundHandlers.onCanvasMouseMove), this.canvasEl.removeEventListener("mouseleave", this.boundHandlers.onCanvasMouseLeave)), document.removeEventListener("pointermove", this.boundHandlers.onPointerMove), document.removeEventListener("pointerup", this.boundHandlers.onPointerUp), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.mutationObserver && (this.mutationObserver.disconnect(), this.mutationObserver = null), this.minimapEl && this.minimapEl.parentNode && this.minimapEl.parentNode.removeChild(this.minimapEl), this.minimapEl = null, this.columnsEl = null, this.canvasEl = null, this.canvasCtx = null, this.viewportEl = null, this.scrollContainer = null, this.columns = []);
707
710
  }
708
711
  }
709
- const I = ':root{--tm-background: #e3f2fd;--tm-border: #90caf9;--tm-viewport-color: rgba(25, 118, 210, .3);--tm-viewport-border: #1976d2;--tm-height: 40px;--tm-column-color: #64b5f6;--tm-column-gap: 1px;--tm-border-radius: 4px;--tm-canvas-empty: #bbdefb;--tm-canvas-filled: #1565c0;--tm-compact-dot-size: 5px;--tm-compact-transition-duration: .18s}@media (prefers-color-scheme: dark){:root{--tm-background: #1a237e;--tm-border: #3949ab;--tm-viewport-color: rgba(100, 180, 255, .3);--tm-viewport-border: #64b5f6;--tm-column-color: #3f51b5;--tm-canvas-empty: #283593;--tm-canvas-filled: #90caf9}}.tm-minimap{position:relative;width:var(--tm-minimap-width, 100%);height:var(--tm-minimap-height, var(--tm-height));background:var(--tm-background);border:1px solid var(--tm-border);border-radius:var(--tm-border-radius);box-sizing:border-box;overflow:hidden;user-select:none;-webkit-user-select:none;cursor:pointer;transition:width var(--tm-compact-transition-duration) ease-in-out,height var(--tm-compact-transition-duration) ease-in-out,opacity var(--tm-compact-transition-duration) ease-in-out,transform var(--tm-compact-transition-duration) ease-in-out,background-color var(--tm-compact-transition-duration) ease-in-out,border-color var(--tm-compact-transition-duration) ease-in-out,box-shadow var(--tm-compact-transition-duration) ease-in-out;will-change:width,height,opacity,transform}.tm-minimap--top{margin-bottom:8px}.tm-minimap--bottom{margin-top:8px}.tm-minimap--fixed{z-index:100;box-shadow:0 4px 12px #00000026;border-radius:8px}.tm-minimap--compact-collapsed{border-radius:999px}.tm-minimap--compact-expanded{border-radius:8px}.tm-minimap--compact>*{transition:opacity var(--tm-compact-transition-duration) ease-in-out}.tm-minimap--compact-collapsed{background:color-mix(in srgb,var(--tm-background) 60%,transparent);border-color:color-mix(in srgb,var(--tm-border) 45%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--tm-border) 20%,transparent);opacity:.92;transform:translate(2px,2px)}.tm-minimap--compact-collapsed>*{opacity:0;pointer-events:none}.tm-minimap--compact-collapsed:after{content:"";position:absolute;right:calc((var(--tm-minimap-width, 24px) - var(--tm-compact-dot-size)) / 2);bottom:calc((var(--tm-minimap-height, 24px) - var(--tm-compact-dot-size)) / 2);width:var(--tm-compact-dot-size);height:var(--tm-compact-dot-size);border-radius:999px;background:color-mix(in srgb,var(--tm-viewport-border) 72%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--tm-viewport-border) 24%,transparent);opacity:.78;pointer-events:none;transition:opacity var(--tm-compact-transition-duration) ease-in-out,transform var(--tm-compact-transition-duration) ease-in-out,background-color var(--tm-compact-transition-duration) ease-in-out}.tm-minimap--compact-expanded{transform:translate(0)}.tm-minimap--compact-expanded:after{opacity:0;transform:scale(.7)}.tm-columns{display:flex;align-items:stretch;height:100%;gap:var(--tm-column-gap);padding:4px;box-sizing:border-box}.tm-column{flex-shrink:0;height:100%;background:var(--tm-column-color);border-radius:2px;transition:background-color .15s ease;cursor:pointer}.tm-column:hover{background:color-mix(in srgb,var(--tm-column-color) 80%,black)}.tm-canvas{width:100%;height:100%;display:block;cursor:pointer}.tm-viewport{position:absolute;top:0;height:100%;background:var(--tm-viewport-color);border-left:2px solid var(--tm-viewport-border);border-right:2px solid var(--tm-viewport-border);box-sizing:border-box;cursor:grab;transition:background-color .15s ease;z-index:10}.tm-viewport:hover{background:color-mix(in srgb,var(--tm-viewport-color) 100%,black 10%)}.tm-viewport--dragging{cursor:grabbing;background:color-mix(in srgb,var(--tm-viewport-color) 100%,black 20%);transition:none}.tm-viewport--disabled{cursor:default;pointer-events:none}.tm-minimap:focus-visible{outline:2px solid var(--tm-viewport-border);outline-offset:2px}.tm-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}';
710
- let z = !1;
712
+ const I = ':root{--tm-background: #e3f2fd;--tm-border: #90caf9;--tm-viewport-color: rgba(25, 118, 210, .3);--tm-viewport-border: #1976d2;--tm-height: 40px;--tm-column-color: #64b5f6;--tm-column-gap: 1px;--tm-border-radius: 4px;--tm-canvas-empty: #bbdefb;--tm-canvas-filled: #1565c0;--tm-compact-dot-size: 5px;--tm-compact-transition-duration: .18s}@media (prefers-color-scheme: dark){:root{--tm-background: #1a237e;--tm-border: #3949ab;--tm-viewport-color: rgba(100, 180, 255, .3);--tm-viewport-border: #64b5f6;--tm-column-color: #3f51b5;--tm-canvas-empty: #283593;--tm-canvas-filled: #90caf9}}.tm-minimap{position:relative;width:var(--tm-minimap-width, 100%);height:var(--tm-minimap-height, var(--tm-height));background:var(--tm-background);border:1px solid var(--tm-border);border-radius:var(--tm-border-radius);box-sizing:border-box;overflow:hidden;user-select:none;-webkit-user-select:none;cursor:pointer;transition:width var(--tm-compact-transition-duration) ease-in-out,height var(--tm-compact-transition-duration) ease-in-out,opacity var(--tm-compact-transition-duration) ease-in-out,transform var(--tm-compact-transition-duration) ease-in-out,background-color var(--tm-compact-transition-duration) ease-in-out,border-color var(--tm-compact-transition-duration) ease-in-out,box-shadow var(--tm-compact-transition-duration) ease-in-out;will-change:width,height,opacity,transform}.tm-minimap--top{margin-bottom:8px}.tm-minimap--bottom{margin-top:8px}.tm-minimap--fixed{z-index:100;box-shadow:0 4px 12px #00000026;border-radius:8px}.tm-minimap--compact-collapsed{border-radius:999px}.tm-minimap--compact-expanded{border-radius:8px}.tm-minimap--compact>*{transition:opacity var(--tm-compact-transition-duration) ease-in-out}.tm-minimap--compact-collapsed{background:color-mix(in srgb,var(--tm-background) 60%,transparent);border-color:color-mix(in srgb,var(--tm-border) 45%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--tm-border) 20%,transparent);opacity:.92;transform:translate(2px,2px)}.tm-minimap--compact-collapsed>*{opacity:0;pointer-events:none}.tm-minimap--compact-collapsed:after{content:"";position:absolute;right:calc((var(--tm-minimap-width, 24px) - var(--tm-compact-dot-size)) / 2);bottom:calc((var(--tm-minimap-height, 24px) - var(--tm-compact-dot-size)) / 2);width:var(--tm-compact-dot-size);height:var(--tm-compact-dot-size);border-radius:999px;background:color-mix(in srgb,var(--tm-viewport-border) 72%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--tm-viewport-border) 24%,transparent);opacity:.78;pointer-events:none;transition:opacity var(--tm-compact-transition-duration) ease-in-out,transform var(--tm-compact-transition-duration) ease-in-out,background-color var(--tm-compact-transition-duration) ease-in-out}.tm-minimap--compact-expanded{transform:translate(0)}.tm-minimap--compact-expanded:after{opacity:0;transform:scale(.7)}.tm-columns{display:flex;align-items:stretch;height:100%;gap:var(--tm-column-gap);padding:4px;box-sizing:border-box}.tm-column{flex:1 1 0;min-width:0;height:100%;background:var(--tm-column-color);border-radius:2px;transition:background-color .15s ease;cursor:pointer}.tm-column:hover{background:color-mix(in srgb,var(--tm-column-color) 80%,black)}.tm-canvas{width:100%;height:100%;display:block;cursor:pointer}.tm-viewport{position:absolute;top:0;height:100%;background:var(--tm-viewport-color);border-left:2px solid var(--tm-viewport-border);border-right:2px solid var(--tm-viewport-border);box-sizing:border-box;cursor:grab;transition:background-color .15s ease;z-index:10}.tm-viewport:hover{background:color-mix(in srgb,var(--tm-viewport-color) 100%,black 10%)}.tm-viewport--dragging{cursor:grabbing;background:color-mix(in srgb,var(--tm-viewport-color) 100%,black 20%);transition:none}.tm-viewport--disabled{cursor:default;pointer-events:none}.tm-minimap:focus-visible{outline:2px solid var(--tm-viewport-border);outline-offset:2px}.tm-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}';
713
+ let W = !1;
711
714
  function Z() {
712
- if (z || typeof document > "u") return;
713
- const u = document.createElement("style");
714
- u.id = "table-minimap-styles", u.textContent = I, document.head.appendChild(u), z = !0;
715
+ if (W || typeof document > "u") return;
716
+ const v = document.createElement("style");
717
+ v.id = "table-minimap-styles", v.textContent = I, document.head.appendChild(v), W = !0;
715
718
  }
716
719
  Z();
717
720
  export {