@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/README.md
CHANGED
|
@@ -8,6 +8,7 @@ A framework-agnostic tab/panel management system with snapping and docking capab
|
|
|
8
8
|
- **Anchor Docking** - Dock panels to predefined screen positions
|
|
9
9
|
- **Drag Modes** - Drag entire groups or detach individual panels
|
|
10
10
|
- **Collapse/Expand** - Panels can be collapsed with automatic repositioning
|
|
11
|
+
- **Pin** - Pin panels to prevent dragging and opt out of auto-hide
|
|
11
12
|
- **Auto-Hide** - Panels can hide after inactivity and show on interaction
|
|
12
13
|
- **Event System** - Subscribe to drag, snap, and collapse events
|
|
13
14
|
- **Fully Typed** - Complete TypeScript support
|
|
@@ -54,6 +55,7 @@ manager.registerPanel('my-panel', document.getElementById('my-panel'), {
|
|
|
54
55
|
});
|
|
55
56
|
|
|
56
57
|
// Position panels and create snap chains
|
|
58
|
+
// positionPanelsFromRight takes IDs right-to-left; createSnapChain takes them left-to-right
|
|
57
59
|
manager.positionPanelsFromRight(['tools', 'settings']);
|
|
58
60
|
manager.createSnapChain(['settings', 'tools']);
|
|
59
61
|
|
|
@@ -99,6 +101,40 @@ const manager = new TabManager({
|
|
|
99
101
|
});
|
|
100
102
|
```
|
|
101
103
|
|
|
104
|
+
## Panel Configuration
|
|
105
|
+
|
|
106
|
+
Each panel accepts the following options via `addPanel(config)`:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
manager.addPanel({
|
|
110
|
+
id: 'my-panel', // Required. Unique identifier.
|
|
111
|
+
title: 'My Panel', // Header text.
|
|
112
|
+
width: 300, // Panel width in px (default: 300).
|
|
113
|
+
initialPosition: { x: 100, y: 100 }, // Starting position. Auto-placed if omitted.
|
|
114
|
+
content: '<div>...</div>', // HTML string or HTMLElement for the content area.
|
|
115
|
+
|
|
116
|
+
// Collapse
|
|
117
|
+
startCollapsed: true, // Whether the panel starts collapsed (default: true).
|
|
118
|
+
collapsible: true, // Show collapse button (default: true).
|
|
119
|
+
|
|
120
|
+
// Pin
|
|
121
|
+
pinnable: false, // Show pin button in header (default: false).
|
|
122
|
+
startPinned: false, // Initial pin state (default: false).
|
|
123
|
+
|
|
124
|
+
// Drag
|
|
125
|
+
draggable: true, // Allow dragging (default: true).
|
|
126
|
+
detachable: true, // Show detach grip for single-panel drag (default: true).
|
|
127
|
+
|
|
128
|
+
// Auto-hide overrides (see Auto-Hide section)
|
|
129
|
+
startHidden: false, // Override global startHidden for this panel.
|
|
130
|
+
autoHideDelay: undefined, // Override global autoHideDelay (0 = disable auto-hide).
|
|
131
|
+
|
|
132
|
+
// Z-index
|
|
133
|
+
zIndex: 1000, // Default z-index (default: 1000).
|
|
134
|
+
dragZIndex: 1002, // Z-index while dragging (default: 1002).
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
102
138
|
## API Reference
|
|
103
139
|
|
|
104
140
|
### TabManager
|
|
@@ -115,12 +151,23 @@ const manager = new TabManager({
|
|
|
115
151
|
- `getSnapChain(panelId)` - Get all panels in same chain
|
|
116
152
|
- `snap(leftPanelId, rightPanelId)` - Manually snap two panels
|
|
117
153
|
- `detach(panelId)` - Detach panel from chain
|
|
118
|
-
- `createSnapChain(panelIds)` - Create chain from panel IDs
|
|
154
|
+
- `createSnapChain(panelIds)` - Create chain from panel IDs (left-to-right order)
|
|
119
155
|
- `updatePositions()` - Recalculate snapped positions
|
|
120
156
|
|
|
121
157
|
#### Positioning
|
|
122
|
-
|
|
123
|
-
|
|
158
|
+
|
|
159
|
+
`positionPanelsFromRight` and `positionPanelsFromLeft` take panel IDs in **opposite orders**:
|
|
160
|
+
|
|
161
|
+
- `positionPanelsFromRight(panelIds, gap?)` — first ID is placed at the **right edge**, rest go leftward. Pass IDs **right-to-left**.
|
|
162
|
+
- `positionPanelsFromLeft(panelIds, gap?)` — first ID is placed at the **left edge**, rest go rightward. Pass IDs **left-to-right**.
|
|
163
|
+
|
|
164
|
+
Because `createSnapChain` uses left-to-right order, you'll typically reverse the array between the two calls:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
// Visual order left-to-right: properties, tools, settings
|
|
168
|
+
manager.positionPanelsFromRight(['settings', 'tools', 'properties']); // right-to-left
|
|
169
|
+
manager.createSnapChain(['properties', 'tools', 'settings']); // left-to-right
|
|
170
|
+
```
|
|
124
171
|
|
|
125
172
|
#### Anchors
|
|
126
173
|
- `addAnchor(config)` - Add custom anchor
|
|
@@ -149,10 +196,54 @@ const manager = new TabManager({
|
|
|
149
196
|
| `snap:panel` | Panels snapped together |
|
|
150
197
|
| `snap:anchor` | Panels snapped to anchor |
|
|
151
198
|
| `panel:detached` | Panel detached from chain |
|
|
199
|
+
| `panel:pin` | Panel pinned/unpinned |
|
|
152
200
|
| `panel:collapse` | Panel collapsed/expanded |
|
|
153
201
|
| `panel:show` | Panel became visible (auto-hide) |
|
|
154
202
|
| `panel:hide` | Panel became hidden (auto-hide) |
|
|
155
203
|
|
|
204
|
+
## Drag Modes
|
|
205
|
+
|
|
206
|
+
Each panel header has two drag zones:
|
|
207
|
+
|
|
208
|
+
- **Detach grip** (small handle on the left of the header) — drags only that panel. It is detached from its snap chain and moved independently.
|
|
209
|
+
- **Title / header area** — drags the entire connected snap chain as a group.
|
|
210
|
+
|
|
211
|
+
Set `detachable: false` to hide the grip and make the header always drag the group.
|
|
212
|
+
|
|
213
|
+
## Pinning
|
|
214
|
+
|
|
215
|
+
Pinning locks a panel in place and exempts it from auto-hide. Enable the pin button with `pinnable: true`:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
manager.addPanel({
|
|
219
|
+
id: 'hud',
|
|
220
|
+
title: 'HUD',
|
|
221
|
+
pinnable: true,
|
|
222
|
+
startPinned: true, // start already pinned
|
|
223
|
+
autoHideDelay: 5000, // pin will override this
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### What pinning does
|
|
228
|
+
|
|
229
|
+
- **Prevents dragging** — a pinned panel cannot be moved, even when dragging its header.
|
|
230
|
+
- **Immune to auto-hide** — a pinned panel is always visible regardless of the `autoHideDelay`. Pinning cancels any pending hide timer and shows the panel if it was hidden. Unpinning restarts the timer.
|
|
231
|
+
- **Splits snap chains on drag** — if a pinned panel sits in the middle of a chain and you drag a neighbour, the chain severs at the pin boundary. Only the panels on the same side as the grabbed panel move; the pinned panel and everything beyond it stay put.
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
// Chain: A — B — [P pinned] — C — D
|
|
235
|
+
// Grabbing B moves [A, B] and severs the B↔P bond.
|
|
236
|
+
// Grabbing C moves [C, D] and severs the P↔C bond.
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Events
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
manager.on('panel:pin', ({ panel, isPinned }) => {
|
|
243
|
+
console.log(`${panel.id} is now ${isPinned ? 'pinned' : 'unpinned'}`);
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
156
247
|
## Multi-Section Panel Content
|
|
157
248
|
|
|
158
249
|
When creating panels with multiple sections (like a command menu with categories), put all sections within a **single `content` string**. Do not use multiple panels or multiple content wrappers—this breaks scrolling and causes content cutoff.
|
|
@@ -231,6 +322,10 @@ manager.addPanel({
|
|
|
231
322
|
| `false` | `3000` | Starts visible, hides after 3s of inactivity |
|
|
232
323
|
| `true` | `3000` | Starts hidden, shows on activity, hides after 3s of inactivity |
|
|
233
324
|
|
|
325
|
+
### Pin interaction
|
|
326
|
+
|
|
327
|
+
Pinning a panel overrides auto-hide entirely for that panel — it stays visible regardless of inactivity. Unpinning re-enables the timer. Each panel is tracked independently; pinning one panel in a group has no effect on its neighbours.
|
|
328
|
+
|
|
234
329
|
### Events
|
|
235
330
|
|
|
236
331
|
```typescript
|
|
@@ -312,11 +407,13 @@ debug.clear();
|
|
|
312
407
|
|
|
313
408
|
The debug panel has a special "focus mode" for reading logs:
|
|
314
409
|
|
|
315
|
-
1. **Hover for
|
|
410
|
+
1. **Hover for configurable delay** → Panel enlarges to 75% of screen with doubled text size (default: 5 seconds, configurable via `hoverDelay`)
|
|
316
411
|
2. **Mouse can move freely** → Panel stays enlarged, won't close on mouse leave
|
|
317
412
|
3. **Click × or backdrop** → Returns to normal size
|
|
318
413
|
|
|
319
|
-
The × button is only visible when enlarged.
|
|
414
|
+
The × button is only visible when enlarged. Set `hoverDelay: 0` to disable the enlarge feature entirely.
|
|
415
|
+
|
|
416
|
+
**Auto-hide interaction:** When hovering a debug panel that has auto-hide enabled, the auto-hide timer is paused so the panel won't disappear before the hover-to-enlarge triggers.
|
|
320
417
|
|
|
321
418
|
### Configuration Options
|
|
322
419
|
|
|
@@ -324,6 +421,7 @@ The × button is only visible when enlarged.
|
|
|
324
421
|
|--------|------|---------|-------------|
|
|
325
422
|
| `maxEntries` | `number` | `50` | Maximum log entries before oldest are removed |
|
|
326
423
|
| `showTimestamps` | `boolean` | `false` | Show timestamps on each entry |
|
|
424
|
+
| `hoverDelay` | `number` | `5000` | Milliseconds to hover before enlarging (0 = disable) |
|
|
327
425
|
|
|
328
426
|
Plus all standard `PanelConfig` options (`id`, `title`, `width`, `initialPosition`, `startCollapsed`, etc.)
|
|
329
427
|
|
|
@@ -334,6 +432,41 @@ Plus all standard `PanelConfig` options (`id`, `title`, `width`, `initialPositio
|
|
|
334
432
|
debug.panel; // PanelState - for advanced manipulation
|
|
335
433
|
```
|
|
336
434
|
|
|
435
|
+
### Embeddable Debug Log
|
|
436
|
+
|
|
437
|
+
You can embed a debug log inside any panel or container element using `createDebugLog()`:
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
const manager = new TabManager();
|
|
441
|
+
|
|
442
|
+
// Create a panel with custom content
|
|
443
|
+
const panel = manager.addPanel({
|
|
444
|
+
id: 'my-panel',
|
|
445
|
+
title: 'My Panel',
|
|
446
|
+
content: '<div id="my-content">Some content</div>',
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// Add a debug log section to the panel
|
|
450
|
+
const logSection = document.createElement('div');
|
|
451
|
+
panel.contentWrapper.appendChild(logSection);
|
|
452
|
+
|
|
453
|
+
// Create the embedded debug log (shares hover-to-enlarge with standalone panels)
|
|
454
|
+
const embeddedLog = manager.createDebugLog(logSection, {
|
|
455
|
+
maxEntries: 20,
|
|
456
|
+
showTimestamps: true,
|
|
457
|
+
hoverDelay: 3000, // 3 second hover delay (0 to disable, default: 5000)
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// Use it like a regular debug panel
|
|
461
|
+
embeddedLog.log('event', { data: 'value' });
|
|
462
|
+
embeddedLog.info('status', { connected: true });
|
|
463
|
+
embeddedLog.warn('warning', { message: 'Low memory' });
|
|
464
|
+
embeddedLog.error('error', { code: 500 });
|
|
465
|
+
embeddedLog.clear();
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
The embedded log supports the same hover-to-enlarge behavior as the standalone debug panel.
|
|
469
|
+
|
|
337
470
|
## CSS Customization
|
|
338
471
|
|
|
339
472
|
Override CSS variables to customize appearance:
|