@blorkfield/blork-tabs 0.3.0 → 0.4.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.
- package/README.md +138 -5
- package/dist/index.cjs +238 -69
- package/dist/index.d.cts +116 -4
- package/dist/index.d.ts +116 -4
- package/dist/index.js +234 -69
- package/dist/styles.css +66 -35
- package/package.json +1 -1
- package/src/AutoHideManager.ts +45 -2
- package/src/DebugPanel.ts +185 -15
- package/src/DragManager.ts +13 -13
- package/src/Panel.ts +37 -0
- package/src/SnapChain.ts +45 -0
- package/src/TabManager.ts +54 -71
- package/src/index.ts +6 -1
- package/src/types.ts +48 -0
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
SnapPreview: () => SnapPreview,
|
|
27
27
|
TabManager: () => TabManager,
|
|
28
28
|
areInSameChain: () => areInSameChain,
|
|
29
|
+
createDebugLog: () => createDebugLog,
|
|
29
30
|
createDebugPanelContent: () => createDebugPanelContent,
|
|
30
31
|
createDebugPanelInterface: () => createDebugPanelInterface,
|
|
31
32
|
createPanelElement: () => createPanelElement,
|
|
@@ -38,16 +39,19 @@ __export(index_exports, {
|
|
|
38
39
|
getDefaultZIndex: () => getDefaultZIndex,
|
|
39
40
|
getDragZIndex: () => getDragZIndex,
|
|
40
41
|
getLeftmostPanel: () => getLeftmostPanel,
|
|
42
|
+
getMovingGroupRespectingPins: () => getMovingGroupRespectingPins,
|
|
41
43
|
getPanelDimensions: () => getPanelDimensions,
|
|
42
44
|
getPanelPosition: () => getPanelPosition,
|
|
43
45
|
getRightmostPanel: () => getRightmostPanel,
|
|
44
46
|
hidePanel: () => hidePanel,
|
|
45
47
|
setPanelPosition: () => setPanelPosition,
|
|
46
48
|
setPanelZIndex: () => setPanelZIndex,
|
|
49
|
+
setupHoverEnlarge: () => setupHoverEnlarge,
|
|
47
50
|
showPanel: () => showPanel,
|
|
48
51
|
snapPanels: () => snapPanels,
|
|
49
52
|
snapPanelsToTarget: () => snapPanelsToTarget,
|
|
50
53
|
toggleCollapse: () => toggleCollapse,
|
|
54
|
+
togglePin: () => togglePin,
|
|
51
55
|
unsnap: () => unsnap,
|
|
52
56
|
updateSnappedPositions: () => updateSnappedPositions
|
|
53
57
|
});
|
|
@@ -65,11 +69,24 @@ function createDebugPanelContent(_config, classes) {
|
|
|
65
69
|
};
|
|
66
70
|
}
|
|
67
71
|
function createDebugPanelInterface(panel, elements, config, classes) {
|
|
72
|
+
const debugLog = createDebugLogInterface(elements.logContainer, config, classes);
|
|
73
|
+
return {
|
|
74
|
+
panel,
|
|
75
|
+
...debugLog
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function escapeHtml(str) {
|
|
79
|
+
const div = document.createElement("div");
|
|
80
|
+
div.textContent = str;
|
|
81
|
+
return div.innerHTML;
|
|
82
|
+
}
|
|
83
|
+
function createDebugLogInterface(logContainer, config, classes) {
|
|
68
84
|
const maxEntries = config.maxEntries ?? 50;
|
|
69
85
|
const showTimestamps = config.showTimestamps ?? false;
|
|
86
|
+
const entryClass = classes.debugLogEntry;
|
|
70
87
|
function addEntry(level, eventName, data) {
|
|
71
88
|
const entry = document.createElement("div");
|
|
72
|
-
entry.className =
|
|
89
|
+
entry.className = entryClass;
|
|
73
90
|
if (level === "warn") entry.classList.add(classes.debugLogEntryWarn);
|
|
74
91
|
if (level === "error") entry.classList.add(classes.debugLogEntryError);
|
|
75
92
|
let html = "";
|
|
@@ -88,30 +105,104 @@ function createDebugPanelInterface(panel, elements, config, classes) {
|
|
|
88
105
|
html += `<span class="${classes.debugLogData}">${escapeHtml(dataStr)}</span>`;
|
|
89
106
|
}
|
|
90
107
|
entry.innerHTML = html;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
108
|
+
logContainer.appendChild(entry);
|
|
109
|
+
logContainer.scrollTop = logContainer.scrollHeight;
|
|
110
|
+
const entries = logContainer.querySelectorAll(`.${entryClass}`);
|
|
111
|
+
if (entries.length > maxEntries) {
|
|
112
|
+
const toRemove = entries.length - maxEntries;
|
|
113
|
+
for (let i = 0; i < toRemove; i++) {
|
|
114
|
+
entries[i].remove();
|
|
115
|
+
}
|
|
95
116
|
}
|
|
96
117
|
}
|
|
118
|
+
function clearEntries() {
|
|
119
|
+
const entries = logContainer.querySelectorAll(`.${entryClass}`);
|
|
120
|
+
entries.forEach((entry) => entry.remove());
|
|
121
|
+
}
|
|
97
122
|
return {
|
|
98
|
-
panel,
|
|
99
123
|
log: (name, data) => addEntry("log", name, data),
|
|
100
124
|
info: (name, data) => addEntry("info", name, data),
|
|
101
125
|
warn: (name, data) => addEntry("warn", name, data),
|
|
102
126
|
error: (name, data) => addEntry("error", name, data),
|
|
103
|
-
clear:
|
|
104
|
-
elements.logContainer.innerHTML = "";
|
|
105
|
-
}
|
|
127
|
+
clear: clearEntries
|
|
106
128
|
};
|
|
107
129
|
}
|
|
108
|
-
function
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
130
|
+
function createDebugLog(container, config, classes) {
|
|
131
|
+
const logContainer = document.createElement("div");
|
|
132
|
+
logContainer.className = classes.debugLog;
|
|
133
|
+
container.appendChild(logContainer);
|
|
134
|
+
const debugLog = createDebugLogInterface(logContainer, config, classes);
|
|
135
|
+
return { debugLog, logContainer };
|
|
136
|
+
}
|
|
137
|
+
function setupHoverEnlarge(config) {
|
|
138
|
+
const { logContainer, hoverDelay, backdropContainer, classes, onHoverStart, onHoverEnd, onClose } = config;
|
|
139
|
+
logContainer.classList.add(classes.debugPanel);
|
|
140
|
+
const closeBtn = document.createElement("button");
|
|
141
|
+
closeBtn.className = classes.debugClearButton;
|
|
142
|
+
closeBtn.textContent = "\xD7";
|
|
143
|
+
closeBtn.title = "Close enlarged view";
|
|
144
|
+
logContainer.appendChild(closeBtn);
|
|
145
|
+
let hoverTimeout = null;
|
|
146
|
+
let isEnlarged = false;
|
|
147
|
+
let backdrop = null;
|
|
148
|
+
let originalParent = null;
|
|
149
|
+
let placeholder = null;
|
|
150
|
+
const closeEnlarged = () => {
|
|
151
|
+
if (!isEnlarged) return;
|
|
152
|
+
isEnlarged = false;
|
|
153
|
+
logContainer.classList.remove(classes.debugPanelEnlarged);
|
|
154
|
+
if (originalParent && placeholder) {
|
|
155
|
+
originalParent.insertBefore(logContainer, placeholder);
|
|
156
|
+
placeholder.remove();
|
|
157
|
+
placeholder = null;
|
|
158
|
+
originalParent = null;
|
|
159
|
+
}
|
|
160
|
+
if (backdrop) {
|
|
161
|
+
backdrop.remove();
|
|
162
|
+
backdrop = null;
|
|
163
|
+
}
|
|
164
|
+
onClose?.();
|
|
165
|
+
};
|
|
166
|
+
const openEnlarged = () => {
|
|
167
|
+
if (isEnlarged) return;
|
|
168
|
+
isEnlarged = true;
|
|
169
|
+
backdrop = document.createElement("div");
|
|
170
|
+
backdrop.className = classes.debugBackdrop;
|
|
171
|
+
backdropContainer.appendChild(backdrop);
|
|
172
|
+
backdrop.addEventListener("click", closeEnlarged);
|
|
173
|
+
originalParent = logContainer.parentElement;
|
|
174
|
+
placeholder = document.createComment("debug-log-placeholder");
|
|
175
|
+
originalParent?.insertBefore(placeholder, logContainer);
|
|
176
|
+
backdropContainer.appendChild(logContainer);
|
|
177
|
+
logContainer.classList.add(classes.debugPanelEnlarged);
|
|
178
|
+
};
|
|
179
|
+
logContainer.addEventListener("mouseenter", () => {
|
|
180
|
+
onHoverStart?.();
|
|
181
|
+
if (isEnlarged) return;
|
|
182
|
+
if (hoverDelay > 0) {
|
|
183
|
+
hoverTimeout = setTimeout(() => {
|
|
184
|
+
openEnlarged();
|
|
185
|
+
}, hoverDelay);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
logContainer.addEventListener("mouseleave", () => {
|
|
189
|
+
if (hoverTimeout) {
|
|
190
|
+
clearTimeout(hoverTimeout);
|
|
191
|
+
hoverTimeout = null;
|
|
192
|
+
}
|
|
193
|
+
if (!isEnlarged) {
|
|
194
|
+
onHoverEnd?.();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
closeBtn.addEventListener("click", (e) => {
|
|
198
|
+
e.stopPropagation();
|
|
199
|
+
closeEnlarged();
|
|
200
|
+
});
|
|
112
201
|
}
|
|
113
202
|
|
|
114
203
|
// src/Panel.ts
|
|
204
|
+
var PIN_ICON_UNPINNED = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:block"><line x1="12" y1="17" x2="12" y2="22"/><path d="M5 17H19V16L17 11V4H7L5 11V16Z"/><line x1="5" y1="11" x2="19" y2="11"/></svg>`;
|
|
205
|
+
var PIN_ICON_PINNED = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:block;transform:rotate(90deg)"><line x1="12" y1="17" x2="12" y2="22"/><path d="M5 17H19V16L17 11V4H7L5 11V16Z"/><line x1="5" y1="11" x2="19" y2="11"/></svg>`;
|
|
115
206
|
function createPanelElement(config, classes) {
|
|
116
207
|
const element = document.createElement("div");
|
|
117
208
|
element.className = classes.panel;
|
|
@@ -134,6 +225,14 @@ function createPanelElement(config, classes) {
|
|
|
134
225
|
title.textContent = config.title;
|
|
135
226
|
header.appendChild(title);
|
|
136
227
|
}
|
|
228
|
+
let pinButton = null;
|
|
229
|
+
if (config.pinnable === true) {
|
|
230
|
+
pinButton = document.createElement("button");
|
|
231
|
+
pinButton.className = classes.pinButton;
|
|
232
|
+
pinButton.id = `${config.id}-pin-btn`;
|
|
233
|
+
pinButton.innerHTML = config.startPinned === true ? PIN_ICON_PINNED : PIN_ICON_UNPINNED;
|
|
234
|
+
header.appendChild(pinButton);
|
|
235
|
+
}
|
|
137
236
|
let collapseButton = null;
|
|
138
237
|
if (config.collapsible !== false) {
|
|
139
238
|
collapseButton = document.createElement("button");
|
|
@@ -160,6 +259,7 @@ function createPanelElement(config, classes) {
|
|
|
160
259
|
return {
|
|
161
260
|
element,
|
|
162
261
|
dragHandle: header,
|
|
262
|
+
pinButton,
|
|
163
263
|
collapseButton,
|
|
164
264
|
contentWrapper,
|
|
165
265
|
detachGrip
|
|
@@ -168,12 +268,14 @@ function createPanelElement(config, classes) {
|
|
|
168
268
|
function createPanelState(config, classes, globalConfig) {
|
|
169
269
|
let element;
|
|
170
270
|
let dragHandle;
|
|
271
|
+
let pinButton;
|
|
171
272
|
let collapseButton;
|
|
172
273
|
let contentWrapper;
|
|
173
274
|
let detachGrip;
|
|
174
275
|
if (config.element) {
|
|
175
276
|
element = config.element;
|
|
176
277
|
dragHandle = config.dragHandle ?? element.querySelector(`.${classes.panelHeader}`);
|
|
278
|
+
pinButton = config.pinButton ?? element.querySelector(`.${classes.pinButton}`);
|
|
177
279
|
collapseButton = config.collapseButton ?? element.querySelector(`.${classes.collapseButton}`);
|
|
178
280
|
contentWrapper = config.contentWrapper ?? element.querySelector(`.${classes.panelContent}`);
|
|
179
281
|
detachGrip = config.detachGrip ?? element.querySelector(`.${classes.detachGrip}`);
|
|
@@ -181,6 +283,7 @@ function createPanelState(config, classes, globalConfig) {
|
|
|
181
283
|
const created = createPanelElement(config, classes);
|
|
182
284
|
element = created.element;
|
|
183
285
|
dragHandle = created.dragHandle;
|
|
286
|
+
pinButton = created.pinButton;
|
|
184
287
|
collapseButton = created.collapseButton;
|
|
185
288
|
contentWrapper = created.contentWrapper;
|
|
186
289
|
detachGrip = created.detachGrip;
|
|
@@ -194,9 +297,11 @@ function createPanelState(config, classes, globalConfig) {
|
|
|
194
297
|
id: config.id,
|
|
195
298
|
element,
|
|
196
299
|
dragHandle,
|
|
300
|
+
pinButton,
|
|
197
301
|
collapseButton,
|
|
198
302
|
contentWrapper,
|
|
199
303
|
detachGrip,
|
|
304
|
+
isPinned: config.startPinned === true,
|
|
200
305
|
isCollapsed: config.startCollapsed !== false,
|
|
201
306
|
snappedTo: null,
|
|
202
307
|
snappedFrom: null,
|
|
@@ -218,6 +323,14 @@ function toggleCollapse(state, classes, collapsed) {
|
|
|
218
323
|
}
|
|
219
324
|
return newState;
|
|
220
325
|
}
|
|
326
|
+
function togglePin(state, pinned) {
|
|
327
|
+
const newState = pinned ?? !state.isPinned;
|
|
328
|
+
state.isPinned = newState;
|
|
329
|
+
if (state.pinButton) {
|
|
330
|
+
state.pinButton.innerHTML = newState ? PIN_ICON_PINNED : PIN_ICON_UNPINNED;
|
|
331
|
+
}
|
|
332
|
+
return newState;
|
|
333
|
+
}
|
|
221
334
|
function showPanel(state, classes) {
|
|
222
335
|
if (!state.isHidden) return;
|
|
223
336
|
state.isHidden = false;
|
|
@@ -395,6 +508,28 @@ function snapPanels(leftPanel, rightPanel) {
|
|
|
395
508
|
leftPanel.snappedTo = rightPanel.id;
|
|
396
509
|
rightPanel.snappedFrom = leftPanel.id;
|
|
397
510
|
}
|
|
511
|
+
function getMovingGroupRespectingPins(grabbedPanel, panels) {
|
|
512
|
+
if (grabbedPanel.isPinned) return [];
|
|
513
|
+
const fullGroup = getConnectedGroup(grabbedPanel, panels);
|
|
514
|
+
const grabbedIndex = fullGroup.indexOf(grabbedPanel);
|
|
515
|
+
const leftPanels = [];
|
|
516
|
+
for (let i = grabbedIndex; i >= 0; i--) {
|
|
517
|
+
if (fullGroup[i].isPinned) {
|
|
518
|
+
unsnap(fullGroup[i], fullGroup[i + 1]);
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
leftPanels.unshift(fullGroup[i]);
|
|
522
|
+
}
|
|
523
|
+
const rightPanels = [];
|
|
524
|
+
for (let i = grabbedIndex + 1; i < fullGroup.length; i++) {
|
|
525
|
+
if (fullGroup[i].isPinned) {
|
|
526
|
+
unsnap(fullGroup[i - 1], fullGroup[i]);
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
rightPanels.push(fullGroup[i]);
|
|
530
|
+
}
|
|
531
|
+
return [...leftPanels, ...rightPanels];
|
|
532
|
+
}
|
|
398
533
|
function unsnap(leftPanel, rightPanel) {
|
|
399
534
|
if (leftPanel.snappedTo === rightPanel.id) {
|
|
400
535
|
leftPanel.snappedTo = null;
|
|
@@ -422,18 +557,18 @@ var DragManager = class {
|
|
|
422
557
|
startDrag(e, panel, mode) {
|
|
423
558
|
e.preventDefault();
|
|
424
559
|
e.stopPropagation();
|
|
425
|
-
const connectedPanels = getConnectedGroup(panel, this.panels);
|
|
426
|
-
const initialGroupPositions = /* @__PURE__ */ new Map();
|
|
427
|
-
for (const p of connectedPanels) {
|
|
428
|
-
const rect2 = p.element.getBoundingClientRect();
|
|
429
|
-
initialGroupPositions.set(p.id, { x: rect2.left, y: rect2.top });
|
|
430
|
-
}
|
|
431
560
|
let movingPanels;
|
|
432
561
|
if (mode === "single") {
|
|
433
562
|
detachFromGroup(panel, this.panels);
|
|
434
563
|
movingPanels = [panel];
|
|
435
564
|
} else {
|
|
436
|
-
movingPanels =
|
|
565
|
+
movingPanels = getMovingGroupRespectingPins(panel, this.panels);
|
|
566
|
+
if (movingPanels.length === 0) return;
|
|
567
|
+
}
|
|
568
|
+
const initialGroupPositions = /* @__PURE__ */ new Map();
|
|
569
|
+
for (const p of movingPanels) {
|
|
570
|
+
const rect2 = p.element.getBoundingClientRect();
|
|
571
|
+
initialGroupPositions.set(p.id, { x: rect2.left, y: rect2.top });
|
|
437
572
|
}
|
|
438
573
|
const rect = panel.element.getBoundingClientRect();
|
|
439
574
|
this.activeDrag = {
|
|
@@ -901,6 +1036,7 @@ var SnapPreview = class {
|
|
|
901
1036
|
var AutoHideManager = class {
|
|
902
1037
|
constructor(panels, classes, callbacks) {
|
|
903
1038
|
this.hideTimers = /* @__PURE__ */ new Map();
|
|
1039
|
+
this.pausedPanels = /* @__PURE__ */ new Set();
|
|
904
1040
|
this.listenersAttached = false;
|
|
905
1041
|
this.panels = panels;
|
|
906
1042
|
this.classes = classes;
|
|
@@ -922,6 +1058,8 @@ var AutoHideManager = class {
|
|
|
922
1058
|
*/
|
|
923
1059
|
handleActivity() {
|
|
924
1060
|
for (const panel of this.panels.values()) {
|
|
1061
|
+
if (panel.isPinned) continue;
|
|
1062
|
+
if (this.pausedPanels.has(panel.id)) continue;
|
|
925
1063
|
if (panel.resolvedAutoHideDelay !== void 0 || panel.isHidden) {
|
|
926
1064
|
this.show(panel, "activity");
|
|
927
1065
|
if (panel.resolvedAutoHideDelay !== void 0) {
|
|
@@ -951,6 +1089,23 @@ var AutoHideManager = class {
|
|
|
951
1089
|
this.hideTimers.delete(panelId);
|
|
952
1090
|
}
|
|
953
1091
|
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Pause auto-hide timer for a panel (e.g., during debug hover)
|
|
1094
|
+
*/
|
|
1095
|
+
pauseTimer(panelId) {
|
|
1096
|
+
this.clearTimer(panelId);
|
|
1097
|
+
this.pausedPanels.add(panelId);
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Resume auto-hide timer for a panel
|
|
1101
|
+
*/
|
|
1102
|
+
resumeTimer(panelId) {
|
|
1103
|
+
this.pausedPanels.delete(panelId);
|
|
1104
|
+
const panel = this.panels.get(panelId);
|
|
1105
|
+
if (panel && panel.resolvedAutoHideDelay !== void 0) {
|
|
1106
|
+
this.scheduleHide(panel);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
954
1109
|
/**
|
|
955
1110
|
* Show a panel
|
|
956
1111
|
*/
|
|
@@ -964,9 +1119,27 @@ var AutoHideManager = class {
|
|
|
964
1119
|
*/
|
|
965
1120
|
hide(panel, trigger) {
|
|
966
1121
|
if (panel.isHidden) return;
|
|
1122
|
+
if (panel.isPinned) return;
|
|
967
1123
|
hidePanel(panel, this.classes);
|
|
968
1124
|
this.callbacks.onHide?.(panel, trigger);
|
|
969
1125
|
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Called when a panel's pin state changes.
|
|
1128
|
+
* Pinning cancels the hide timer and reveals the panel if hidden.
|
|
1129
|
+
* Unpinning restarts the timer if the panel participates in auto-hide.
|
|
1130
|
+
*/
|
|
1131
|
+
onPanelPinChanged(panel) {
|
|
1132
|
+
if (panel.isPinned) {
|
|
1133
|
+
this.clearTimer(panel.id);
|
|
1134
|
+
if (panel.isHidden) {
|
|
1135
|
+
this.show(panel, "api");
|
|
1136
|
+
}
|
|
1137
|
+
} else {
|
|
1138
|
+
if (!panel.isHidden && panel.resolvedAutoHideDelay !== void 0) {
|
|
1139
|
+
this.scheduleHide(panel);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
970
1143
|
/**
|
|
971
1144
|
* Initialize a newly added panel's auto-hide state
|
|
972
1145
|
*/
|
|
@@ -1021,6 +1194,7 @@ function generateClasses(prefix) {
|
|
|
1021
1194
|
panelContent: `${prefix}-content`,
|
|
1022
1195
|
panelContentCollapsed: `${prefix}-content-collapsed`,
|
|
1023
1196
|
detachGrip: `${prefix}-detach-grip`,
|
|
1197
|
+
pinButton: `${prefix}-pin-btn`,
|
|
1024
1198
|
collapseButton: `${prefix}-collapse-btn`,
|
|
1025
1199
|
snapPreview: `${prefix}-snap-preview`,
|
|
1026
1200
|
snapPreviewVisible: `${prefix}-snap-preview-visible`,
|
|
@@ -1111,6 +1285,7 @@ var TabManager = class {
|
|
|
1111
1285
|
id,
|
|
1112
1286
|
element,
|
|
1113
1287
|
dragHandle: options.dragHandle,
|
|
1288
|
+
pinButton: options.pinButton,
|
|
1114
1289
|
collapseButton: options.collapseButton,
|
|
1115
1290
|
contentWrapper: options.contentWrapper,
|
|
1116
1291
|
detachGrip: options.detachGrip,
|
|
@@ -1157,58 +1332,38 @@ var TabManager = class {
|
|
|
1157
1332
|
startCollapsed: config.startCollapsed ?? true
|
|
1158
1333
|
};
|
|
1159
1334
|
const state = this.addPanel(panelConfig);
|
|
1160
|
-
state.element.classList.add(this.classes.debugPanel);
|
|
1161
|
-
const closeBtn = document.createElement("button");
|
|
1162
|
-
closeBtn.className = this.classes.debugClearButton;
|
|
1163
|
-
closeBtn.textContent = "\xD7";
|
|
1164
|
-
closeBtn.title = "Close enlarged view";
|
|
1165
|
-
if (state.collapseButton) {
|
|
1166
|
-
state.collapseButton.parentElement?.insertBefore(closeBtn, state.collapseButton);
|
|
1167
|
-
}
|
|
1168
|
-
elements.clearButton = closeBtn;
|
|
1169
1335
|
this.debugPanelElements.set(state.id, elements);
|
|
1170
1336
|
const debugPanel = createDebugPanelInterface(state, elements, config, this.classes);
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
}
|
|
1184
|
-
};
|
|
1185
|
-
const openEnlarged = () => {
|
|
1186
|
-
if (isEnlarged) return;
|
|
1187
|
-
isEnlarged = true;
|
|
1188
|
-
backdrop = document.createElement("div");
|
|
1189
|
-
backdrop.className = backdropClass;
|
|
1190
|
-
this.config.container.appendChild(backdrop);
|
|
1191
|
-
backdrop.addEventListener("click", closeEnlarged);
|
|
1192
|
-
state.element.classList.add(enlargedClass);
|
|
1193
|
-
};
|
|
1194
|
-
state.element.addEventListener("mouseenter", () => {
|
|
1195
|
-
if (isEnlarged) return;
|
|
1196
|
-
hoverTimeout = setTimeout(() => {
|
|
1197
|
-
openEnlarged();
|
|
1198
|
-
}, 5e3);
|
|
1199
|
-
});
|
|
1200
|
-
state.element.addEventListener("mouseleave", () => {
|
|
1201
|
-
if (hoverTimeout) {
|
|
1202
|
-
clearTimeout(hoverTimeout);
|
|
1203
|
-
hoverTimeout = null;
|
|
1204
|
-
}
|
|
1205
|
-
});
|
|
1206
|
-
closeBtn.addEventListener("click", (e) => {
|
|
1207
|
-
e.stopPropagation();
|
|
1208
|
-
closeEnlarged();
|
|
1209
|
-
});
|
|
1337
|
+
const hoverDelay = config.hoverDelay ?? 5e3;
|
|
1338
|
+
if (hoverDelay > 0) {
|
|
1339
|
+
setupHoverEnlarge({
|
|
1340
|
+
logContainer: elements.logContainer,
|
|
1341
|
+
hoverDelay,
|
|
1342
|
+
backdropContainer: this.config.container,
|
|
1343
|
+
classes: this.classes,
|
|
1344
|
+
onHoverStart: () => this.autoHideManager.pauseTimer(state.id),
|
|
1345
|
+
onHoverEnd: () => this.autoHideManager.resumeTimer(state.id),
|
|
1346
|
+
onClose: () => this.autoHideManager.resumeTimer(state.id)
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1210
1349
|
return debugPanel;
|
|
1211
1350
|
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Create an embeddable debug log in any container element
|
|
1353
|
+
*/
|
|
1354
|
+
createDebugLog(container, config = {}) {
|
|
1355
|
+
const { debugLog, logContainer } = createDebugLog(container, config, this.classes);
|
|
1356
|
+
const hoverDelay = config.hoverDelay ?? 5e3;
|
|
1357
|
+
if (hoverDelay > 0) {
|
|
1358
|
+
setupHoverEnlarge({
|
|
1359
|
+
logContainer,
|
|
1360
|
+
hoverDelay,
|
|
1361
|
+
backdropContainer: this.config.container,
|
|
1362
|
+
classes: this.classes
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
return debugLog;
|
|
1366
|
+
}
|
|
1212
1367
|
/**
|
|
1213
1368
|
* Set up event handlers for a panel
|
|
1214
1369
|
*/
|
|
@@ -1220,15 +1375,25 @@ var TabManager = class {
|
|
|
1220
1375
|
this.emit("panel:collapse", { panel: state, isCollapsed: newState });
|
|
1221
1376
|
});
|
|
1222
1377
|
}
|
|
1378
|
+
if (state.pinButton) {
|
|
1379
|
+
state.pinButton.addEventListener("click", () => {
|
|
1380
|
+
const isPinned = togglePin(state);
|
|
1381
|
+
this.autoHideManager.onPanelPinChanged(state);
|
|
1382
|
+
this.emit("panel:pin", { panel: state, isPinned });
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1223
1385
|
if (state.detachGrip) {
|
|
1224
1386
|
state.detachGrip.addEventListener("mousedown", (e) => {
|
|
1387
|
+
if (state.isPinned) return;
|
|
1225
1388
|
this.dragManager.startDrag(e, state, "single");
|
|
1226
1389
|
});
|
|
1227
1390
|
}
|
|
1228
1391
|
state.dragHandle.addEventListener("mousedown", (e) => {
|
|
1229
|
-
|
|
1392
|
+
const target = e.target;
|
|
1393
|
+
if (e.target === state.collapseButton || e.target === state.detachGrip || state.pinButton && state.pinButton.contains(target)) {
|
|
1230
1394
|
return;
|
|
1231
1395
|
}
|
|
1396
|
+
if (state.isPinned) return;
|
|
1232
1397
|
this.dragManager.startDrag(e, state, "group");
|
|
1233
1398
|
});
|
|
1234
1399
|
}
|
|
@@ -1476,6 +1641,7 @@ var TabManager = class {
|
|
|
1476
1641
|
SnapPreview,
|
|
1477
1642
|
TabManager,
|
|
1478
1643
|
areInSameChain,
|
|
1644
|
+
createDebugLog,
|
|
1479
1645
|
createDebugPanelContent,
|
|
1480
1646
|
createDebugPanelInterface,
|
|
1481
1647
|
createPanelElement,
|
|
@@ -1488,16 +1654,19 @@ var TabManager = class {
|
|
|
1488
1654
|
getDefaultZIndex,
|
|
1489
1655
|
getDragZIndex,
|
|
1490
1656
|
getLeftmostPanel,
|
|
1657
|
+
getMovingGroupRespectingPins,
|
|
1491
1658
|
getPanelDimensions,
|
|
1492
1659
|
getPanelPosition,
|
|
1493
1660
|
getRightmostPanel,
|
|
1494
1661
|
hidePanel,
|
|
1495
1662
|
setPanelPosition,
|
|
1496
1663
|
setPanelZIndex,
|
|
1664
|
+
setupHoverEnlarge,
|
|
1497
1665
|
showPanel,
|
|
1498
1666
|
snapPanels,
|
|
1499
1667
|
snapPanelsToTarget,
|
|
1500
1668
|
toggleCollapse,
|
|
1669
|
+
togglePin,
|
|
1501
1670
|
unsnap,
|
|
1502
1671
|
updateSnappedPositions
|
|
1503
1672
|
});
|