@blorkfield/blork-tabs 0.1.3
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/LICENSE +21 -0
- package/README.md +166 -0
- package/dist/index.cjs +1194 -0
- package/dist/index.d.cts +669 -0
- package/dist/index.d.ts +669 -0
- package/dist/index.js +1143 -0
- package/dist/styles.css +186 -0
- package/package.json +62 -0
- package/src/AnchorManager.ts +395 -0
- package/src/DragManager.ts +251 -0
- package/src/Panel.ts +211 -0
- package/src/SnapChain.ts +289 -0
- package/src/SnapPreview.ts +91 -0
- package/src/TabManager.ts +507 -0
- package/src/index.test.ts +9 -0
- package/src/index.ts +105 -0
- package/src/types.ts +320 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @blorkfield/blork-tabs - Type Definitions
|
|
3
|
+
* A framework-agnostic tab/panel management system with snapping and docking
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ==================== Configuration Types ====================
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for initializing the TabManager
|
|
10
|
+
*/
|
|
11
|
+
export interface TabManagerConfig {
|
|
12
|
+
/** Distance threshold for panel-to-panel snapping (default: 50) */
|
|
13
|
+
snapThreshold?: number;
|
|
14
|
+
/** Gap between snapped panels (default: 0) */
|
|
15
|
+
panelGap?: number;
|
|
16
|
+
/** Margin from window edges (default: 16) */
|
|
17
|
+
panelMargin?: number;
|
|
18
|
+
/** Distance threshold for anchor snapping (default: 80) */
|
|
19
|
+
anchorThreshold?: number;
|
|
20
|
+
/** Default panel width for anchor calculations (default: 300) */
|
|
21
|
+
defaultPanelWidth?: number;
|
|
22
|
+
/** Container element for panels (default: document.body) */
|
|
23
|
+
container?: HTMLElement;
|
|
24
|
+
/** Whether to automatically initialize default anchors (default: true) */
|
|
25
|
+
initializeDefaultAnchors?: boolean;
|
|
26
|
+
/** Custom CSS class prefix (default: 'blork-tabs') */
|
|
27
|
+
classPrefix?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resolved configuration with all defaults applied
|
|
32
|
+
*/
|
|
33
|
+
export interface ResolvedTabManagerConfig {
|
|
34
|
+
snapThreshold: number;
|
|
35
|
+
panelGap: number;
|
|
36
|
+
panelMargin: number;
|
|
37
|
+
anchorThreshold: number;
|
|
38
|
+
defaultPanelWidth: number;
|
|
39
|
+
container: HTMLElement;
|
|
40
|
+
initializeDefaultAnchors: boolean;
|
|
41
|
+
classPrefix: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Configuration for creating a new panel
|
|
46
|
+
*/
|
|
47
|
+
export interface PanelConfig {
|
|
48
|
+
/** Unique identifier for the panel */
|
|
49
|
+
id: string;
|
|
50
|
+
/** Panel title displayed in header */
|
|
51
|
+
title?: string;
|
|
52
|
+
/** Initial width (default: 300) */
|
|
53
|
+
width?: number;
|
|
54
|
+
/** Initial collapsed state (default: true) */
|
|
55
|
+
startCollapsed?: boolean;
|
|
56
|
+
/** Initial position (optional - will be auto-positioned if not provided) */
|
|
57
|
+
initialPosition?: { x: number; y: number };
|
|
58
|
+
/** Content element or HTML string */
|
|
59
|
+
content?: HTMLElement | string;
|
|
60
|
+
/** Custom panel element (for existing DOM panels) */
|
|
61
|
+
element?: HTMLDivElement;
|
|
62
|
+
/** Custom drag handle element */
|
|
63
|
+
dragHandle?: HTMLDivElement;
|
|
64
|
+
/** Custom collapse button element */
|
|
65
|
+
collapseButton?: HTMLButtonElement;
|
|
66
|
+
/** Custom content wrapper element */
|
|
67
|
+
contentWrapper?: HTMLDivElement;
|
|
68
|
+
/** Custom detach grip element */
|
|
69
|
+
detachGrip?: HTMLDivElement;
|
|
70
|
+
/** Whether panel can be collapsed (default: true) */
|
|
71
|
+
collapsible?: boolean;
|
|
72
|
+
/** Whether panel can be detached from group (default: true) */
|
|
73
|
+
detachable?: boolean;
|
|
74
|
+
/** Whether panel can be dragged (default: true) */
|
|
75
|
+
draggable?: boolean;
|
|
76
|
+
/** Z-index for panel (default: 1000) */
|
|
77
|
+
zIndex?: number;
|
|
78
|
+
/** Z-index when dragging (default: 1002) */
|
|
79
|
+
dragZIndex?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Configuration for anchor points
|
|
84
|
+
*/
|
|
85
|
+
export interface AnchorConfig {
|
|
86
|
+
/** Unique identifier for the anchor */
|
|
87
|
+
id: string;
|
|
88
|
+
/** Function that returns the anchor position (allows dynamic positioning) */
|
|
89
|
+
getPosition: () => Position;
|
|
90
|
+
/** Whether to show visual indicator (default: true) */
|
|
91
|
+
showIndicator?: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Preset anchor positions
|
|
96
|
+
*/
|
|
97
|
+
export type AnchorPreset =
|
|
98
|
+
| 'top-left'
|
|
99
|
+
| 'top-right'
|
|
100
|
+
| 'top-center'
|
|
101
|
+
| 'bottom-left'
|
|
102
|
+
| 'bottom-right'
|
|
103
|
+
| 'bottom-center'
|
|
104
|
+
| 'center-left'
|
|
105
|
+
| 'center-right';
|
|
106
|
+
|
|
107
|
+
// ==================== State Types ====================
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Current state of a panel
|
|
111
|
+
*/
|
|
112
|
+
export interface PanelState {
|
|
113
|
+
/** Unique panel identifier */
|
|
114
|
+
id: string;
|
|
115
|
+
/** DOM element for the panel */
|
|
116
|
+
element: HTMLDivElement;
|
|
117
|
+
/** Drag handle element */
|
|
118
|
+
dragHandle: HTMLDivElement;
|
|
119
|
+
/** Collapse button element (if collapsible) */
|
|
120
|
+
collapseButton: HTMLButtonElement | null;
|
|
121
|
+
/** Content wrapper element */
|
|
122
|
+
contentWrapper: HTMLDivElement;
|
|
123
|
+
/** Detach grip element (if detachable) */
|
|
124
|
+
detachGrip: HTMLDivElement | null;
|
|
125
|
+
/** Whether panel is currently collapsed */
|
|
126
|
+
isCollapsed: boolean;
|
|
127
|
+
/** ID of panel this is snapped to on its right (outgoing link) */
|
|
128
|
+
snappedTo: string | null;
|
|
129
|
+
/** ID of panel snapped to this on its left (incoming link) */
|
|
130
|
+
snappedFrom: string | null;
|
|
131
|
+
/** Panel configuration */
|
|
132
|
+
config: PanelConfig;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Current drag operation state
|
|
137
|
+
*/
|
|
138
|
+
export interface DragState {
|
|
139
|
+
/** Panel that initiated the drag */
|
|
140
|
+
grabbedPanel: PanelState;
|
|
141
|
+
/** Mouse offset from panel left edge */
|
|
142
|
+
offsetX: number;
|
|
143
|
+
/** Mouse offset from panel top edge */
|
|
144
|
+
offsetY: number;
|
|
145
|
+
/** Initial positions of all connected panels */
|
|
146
|
+
initialGroupPositions: Map<string, Position>;
|
|
147
|
+
/** Panels being moved in this drag operation */
|
|
148
|
+
movingPanels: PanelState[];
|
|
149
|
+
/** Drag mode - single panel or entire group */
|
|
150
|
+
mode: DragMode;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Drag mode determines what gets moved
|
|
155
|
+
*/
|
|
156
|
+
export type DragMode = 'single' | 'group';
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Anchor state including visual indicator
|
|
160
|
+
*/
|
|
161
|
+
export interface AnchorState {
|
|
162
|
+
/** Anchor configuration */
|
|
163
|
+
config: AnchorConfig;
|
|
164
|
+
/** Visual indicator element */
|
|
165
|
+
indicator: HTMLDivElement | null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ==================== Result Types ====================
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Result of snap target detection
|
|
172
|
+
*/
|
|
173
|
+
export interface SnapTarget {
|
|
174
|
+
/** ID of the target panel */
|
|
175
|
+
targetId: string;
|
|
176
|
+
/** Which side of target to snap to */
|
|
177
|
+
side: SnapSide;
|
|
178
|
+
/** X position for snap */
|
|
179
|
+
x: number;
|
|
180
|
+
/** Y position for snap */
|
|
181
|
+
y: number;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Side of panel to snap to
|
|
186
|
+
*/
|
|
187
|
+
export type SnapSide = 'left' | 'right';
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Result of anchor snap detection
|
|
191
|
+
*/
|
|
192
|
+
export interface AnchorSnapResult {
|
|
193
|
+
/** The matched anchor */
|
|
194
|
+
anchor: AnchorState;
|
|
195
|
+
/** Index of panel in group that docks to anchor */
|
|
196
|
+
dockPanelIndex: number;
|
|
197
|
+
/** Final positions for all panels in the group */
|
|
198
|
+
positions: Position[];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Simple x,y position
|
|
203
|
+
*/
|
|
204
|
+
export interface Position {
|
|
205
|
+
x: number;
|
|
206
|
+
y: number;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Bounding rectangle
|
|
211
|
+
*/
|
|
212
|
+
export interface Bounds {
|
|
213
|
+
left: number;
|
|
214
|
+
right: number;
|
|
215
|
+
top: number;
|
|
216
|
+
bottom: number;
|
|
217
|
+
width: number;
|
|
218
|
+
height: number;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ==================== Event Types ====================
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Events emitted by TabManager
|
|
225
|
+
*/
|
|
226
|
+
export interface TabManagerEvents {
|
|
227
|
+
/** Fired when a panel is added */
|
|
228
|
+
'panel:added': PanelAddedEvent;
|
|
229
|
+
/** Fired when a panel is removed */
|
|
230
|
+
'panel:removed': PanelRemovedEvent;
|
|
231
|
+
/** Fired when a panel starts being dragged */
|
|
232
|
+
'drag:start': DragStartEvent;
|
|
233
|
+
/** Fired during drag movement */
|
|
234
|
+
'drag:move': DragMoveEvent;
|
|
235
|
+
/** Fired when drag ends */
|
|
236
|
+
'drag:end': DragEndEvent;
|
|
237
|
+
/** Fired when panels snap together */
|
|
238
|
+
'snap:panel': PanelSnapEvent;
|
|
239
|
+
/** Fired when panels snap to anchor */
|
|
240
|
+
'snap:anchor': AnchorSnapEvent;
|
|
241
|
+
/** Fired when a panel is detached from group */
|
|
242
|
+
'panel:detached': PanelDetachedEvent;
|
|
243
|
+
/** Fired when panel collapse state changes */
|
|
244
|
+
'panel:collapse': PanelCollapseEvent;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface PanelAddedEvent {
|
|
248
|
+
panel: PanelState;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface PanelRemovedEvent {
|
|
252
|
+
panelId: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface DragStartEvent {
|
|
256
|
+
panel: PanelState;
|
|
257
|
+
mode: DragMode;
|
|
258
|
+
movingPanels: PanelState[];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export interface DragMoveEvent {
|
|
262
|
+
panel: PanelState;
|
|
263
|
+
position: Position;
|
|
264
|
+
snapTarget: SnapTarget | null;
|
|
265
|
+
anchorTarget: AnchorSnapResult | null;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface DragEndEvent {
|
|
269
|
+
panel: PanelState;
|
|
270
|
+
finalPosition: Position;
|
|
271
|
+
snappedToPanel: boolean;
|
|
272
|
+
snappedToAnchor: boolean;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export interface PanelSnapEvent {
|
|
276
|
+
movingPanels: PanelState[];
|
|
277
|
+
targetPanel: PanelState;
|
|
278
|
+
side: SnapSide;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface AnchorSnapEvent {
|
|
282
|
+
movingPanels: PanelState[];
|
|
283
|
+
anchor: AnchorState;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export interface PanelDetachedEvent {
|
|
287
|
+
panel: PanelState;
|
|
288
|
+
previousGroup: PanelState[];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export interface PanelCollapseEvent {
|
|
292
|
+
panel: PanelState;
|
|
293
|
+
isCollapsed: boolean;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Event listener function type
|
|
298
|
+
*/
|
|
299
|
+
export type EventListener<T> = (event: T) => void;
|
|
300
|
+
|
|
301
|
+
// ==================== CSS Class Names ====================
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* CSS class names used by the library
|
|
305
|
+
*/
|
|
306
|
+
export interface CSSClasses {
|
|
307
|
+
panel: string;
|
|
308
|
+
panelHeader: string;
|
|
309
|
+
panelTitle: string;
|
|
310
|
+
panelContent: string;
|
|
311
|
+
panelContentCollapsed: string;
|
|
312
|
+
detachGrip: string;
|
|
313
|
+
collapseButton: string;
|
|
314
|
+
snapPreview: string;
|
|
315
|
+
snapPreviewVisible: string;
|
|
316
|
+
anchorIndicator: string;
|
|
317
|
+
anchorIndicatorVisible: string;
|
|
318
|
+
anchorIndicatorActive: string;
|
|
319
|
+
dragging: string;
|
|
320
|
+
}
|