@framesquared/dd 0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 John Carbone
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,221 @@
1
+ /**
2
+ * @framesquared/dd – Draggable
3
+ *
4
+ * Makes an element draggable. Supports drag handles, axis lock,
5
+ * snap-to-grid, constraint, and proxy modes. Integrates with
6
+ * DragManager for drop target detection.
7
+ */
8
+
9
+ interface DraggableConfig {
10
+ el: HTMLElement;
11
+ handle?: string;
12
+ constrainTo?: HTMLElement | 'parent' | 'viewport';
13
+ axis?: 'x' | 'y';
14
+ snap?: {
15
+ x: number;
16
+ y: number;
17
+ };
18
+ proxy?: boolean;
19
+ ghostCls?: string;
20
+ groups?: string[];
21
+ disabled?: boolean;
22
+ threshold?: number;
23
+ data?: Record<string, unknown>;
24
+ onDragStart?: (data: DragData) => void;
25
+ onDrag?: (data: DragData) => void;
26
+ onDragEnd?: (data: DragData) => void;
27
+ }
28
+ declare class Draggable {
29
+ readonly el: HTMLElement;
30
+ private handle;
31
+ private constrainTo;
32
+ private axis;
33
+ private snap;
34
+ private useProxy;
35
+ private groups;
36
+ private disabled;
37
+ private threshold;
38
+ private userData;
39
+ private onDragStartCb;
40
+ private onDragCb;
41
+ private onDragEndCb;
42
+ private startX;
43
+ private startY;
44
+ private elStartX;
45
+ private elStartY;
46
+ private _dragging;
47
+ private _started;
48
+ private dragData;
49
+ private moveHandler;
50
+ private upHandler;
51
+ constructor(config: DraggableConfig);
52
+ private onPointerDown;
53
+ private onPointerMove;
54
+ private onPointerUp;
55
+ private getConstrainBounds;
56
+ setDisabled(disabled: boolean): void;
57
+ destroy(): void;
58
+ }
59
+
60
+ /**
61
+ * @framesquared/dd – DragData
62
+ * Payload carried during a drag operation.
63
+ */
64
+
65
+ interface DragData {
66
+ source: Draggable;
67
+ sourceEl: HTMLElement;
68
+ groups: string[];
69
+ data: Record<string, unknown>;
70
+ startX: number;
71
+ startY: number;
72
+ currentX: number;
73
+ currentY: number;
74
+ }
75
+
76
+ /**
77
+ * @framesquared/dd – DragManager
78
+ *
79
+ * Singleton that manages all drag operations globally.
80
+ * Tracks registered Droppables and coordinates hit-testing
81
+ * during active drags.
82
+ */
83
+
84
+ interface DropTarget {
85
+ el: HTMLElement;
86
+ accept: string[];
87
+ disabled: boolean;
88
+ overCls: string;
89
+ onDragEnter?: (data: DragData) => boolean | void;
90
+ onDragOver?: (data: DragData) => void;
91
+ onDragLeave?: (data: DragData) => void;
92
+ onDrop?: (data: DragData) => boolean | void;
93
+ }
94
+ declare const DragManager: {
95
+ isDragging(): boolean;
96
+ setDragging(value: boolean): void;
97
+ registerDropTarget(target: DropTarget): void;
98
+ unregisterDropTarget(target: DropTarget): void;
99
+ /** Called during pointermove to check drop targets. */
100
+ notifyMove(data: DragData, x: number, y: number): void;
101
+ /** Called on pointerup to finalize drop. */
102
+ notifyDrop(data: DragData, _x: number, _y: number): boolean;
103
+ reset(): void;
104
+ };
105
+
106
+ /**
107
+ * @framesquared/dd – Droppable
108
+ *
109
+ * Makes an element a drop target. Registers with DragManager
110
+ * for hit testing during active drags.
111
+ */
112
+
113
+ interface DroppableConfig {
114
+ el: HTMLElement;
115
+ accept?: string[];
116
+ overCls?: string;
117
+ disabled?: boolean;
118
+ onDragEnter?: (data: DragData) => boolean | void;
119
+ onDragOver?: (data: DragData) => void;
120
+ onDragLeave?: (data: DragData) => void;
121
+ onDrop?: (data: DragData) => boolean | void;
122
+ }
123
+ declare class Droppable {
124
+ readonly el: HTMLElement;
125
+ private target;
126
+ constructor(config: DroppableConfig);
127
+ setDisabled(disabled: boolean): void;
128
+ destroy(): void;
129
+ }
130
+
131
+ /**
132
+ * @framesquared/dd – DragProxy
133
+ * Visual feedback during drag — a ghost element that follows the cursor.
134
+ */
135
+ interface DragProxyConfig {
136
+ sourceEl: HTMLElement;
137
+ ghostCls?: string;
138
+ }
139
+ declare class DragProxy {
140
+ private ghostEl;
141
+ private ghostCls;
142
+ private sourceEl;
143
+ constructor(config: DragProxyConfig);
144
+ show(x: number, y: number): void;
145
+ moveTo(x: number, y: number): void;
146
+ setStatus(valid: boolean): void;
147
+ hide(): void;
148
+ getEl(): HTMLElement | null;
149
+ }
150
+
151
+ /**
152
+ * @framesquared/dd – Sortable
153
+ *
154
+ * Makes items within a container sortable by drag.
155
+ * Provides moveItem() for programmatic reordering
156
+ * and fires sort/start/end events.
157
+ */
158
+ interface SortableConfig {
159
+ el: HTMLElement;
160
+ itemSelector: string;
161
+ handle?: string;
162
+ axis?: 'x' | 'y';
163
+ group?: string;
164
+ ghostClass?: string;
165
+ onSort?: (oldIndex: number, newIndex: number) => void;
166
+ onStart?: (index: number) => void;
167
+ onEnd?: (index: number) => void;
168
+ }
169
+ declare class Sortable {
170
+ private el;
171
+ private itemSelector;
172
+ private onSortCb;
173
+ private onStartCb;
174
+ private onEndCb;
175
+ constructor(config: SortableConfig);
176
+ getItems(): HTMLElement[];
177
+ getOrder(): string[];
178
+ moveItem(fromIndex: number, toIndex: number): void;
179
+ destroy(): void;
180
+ }
181
+
182
+ /**
183
+ * @framesquared/dd – Resizable
184
+ *
185
+ * Makes an element resizable by adding drag handles on specified
186
+ * edges/corners. Supports min/max constraints and aspect ratio
187
+ * preservation.
188
+ */
189
+ interface ResizableConfig {
190
+ el: HTMLElement;
191
+ handles: string;
192
+ minWidth?: number;
193
+ maxWidth?: number;
194
+ minHeight?: number;
195
+ maxHeight?: number;
196
+ preserveRatio?: boolean;
197
+ onResize?: (width: number, height: number) => void;
198
+ onResizeStart?: () => void;
199
+ onResizeEnd?: () => void;
200
+ }
201
+ declare class Resizable {
202
+ private el;
203
+ private handles;
204
+ private minW;
205
+ private maxW;
206
+ private minH;
207
+ private maxH;
208
+ private preserveRatio;
209
+ private initialRatio;
210
+ private onResizeCb;
211
+ private onResizeStartCb;
212
+ private onResizeEndCb;
213
+ private handleEls;
214
+ constructor(config: ResizableConfig);
215
+ private createHandles;
216
+ private positionHandle;
217
+ private onHandleDown;
218
+ destroy(): void;
219
+ }
220
+
221
+ export { type DragData, DragManager, DragProxy, type DragProxyConfig, Draggable, type DraggableConfig, type DropTarget, Droppable, type DroppableConfig, Resizable, type ResizableConfig, Sortable, type SortableConfig };
package/dist/index.js ADDED
@@ -0,0 +1,517 @@
1
+ // src/DragManager.ts
2
+ var dragging = false;
3
+ var dropTargets = [];
4
+ var currentOverTarget = null;
5
+ function hitTest(target, x, y) {
6
+ const rect = target.el.getBoundingClientRect();
7
+ return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
8
+ }
9
+ function groupsMatch(dragGroups, acceptGroups) {
10
+ if (acceptGroups.length === 0) return true;
11
+ return dragGroups.some((g) => acceptGroups.includes(g));
12
+ }
13
+ var DragManager = {
14
+ isDragging() {
15
+ return dragging;
16
+ },
17
+ setDragging(value) {
18
+ dragging = value;
19
+ },
20
+ registerDropTarget(target) {
21
+ if (!dropTargets.includes(target)) dropTargets.push(target);
22
+ },
23
+ unregisterDropTarget(target) {
24
+ const idx = dropTargets.indexOf(target);
25
+ if (idx >= 0) dropTargets.splice(idx, 1);
26
+ },
27
+ /** Called during pointermove to check drop targets. */
28
+ notifyMove(data, x, y) {
29
+ let overTarget = null;
30
+ for (const target of dropTargets) {
31
+ if (target.disabled) continue;
32
+ if (!groupsMatch(data.groups, target.accept)) continue;
33
+ if (hitTest(target, x, y)) {
34
+ overTarget = target;
35
+ break;
36
+ }
37
+ }
38
+ if (currentOverTarget && currentOverTarget !== overTarget) {
39
+ if (currentOverTarget.overCls) {
40
+ currentOverTarget.el.classList.remove(currentOverTarget.overCls);
41
+ }
42
+ currentOverTarget.onDragLeave?.(data);
43
+ currentOverTarget = null;
44
+ }
45
+ if (overTarget && overTarget !== currentOverTarget) {
46
+ currentOverTarget = overTarget;
47
+ if (overTarget.overCls) {
48
+ overTarget.el.classList.add(overTarget.overCls);
49
+ }
50
+ overTarget.onDragEnter?.(data);
51
+ }
52
+ if (currentOverTarget) {
53
+ currentOverTarget.onDragOver?.(data);
54
+ }
55
+ },
56
+ /** Called on pointerup to finalize drop. */
57
+ notifyDrop(data, _x, _y) {
58
+ let dropped = false;
59
+ if (currentOverTarget) {
60
+ if (currentOverTarget.overCls) {
61
+ currentOverTarget.el.classList.remove(currentOverTarget.overCls);
62
+ }
63
+ currentOverTarget.onDrop?.(data);
64
+ dropped = true;
65
+ currentOverTarget = null;
66
+ }
67
+ return dropped;
68
+ },
69
+ reset() {
70
+ dragging = false;
71
+ currentOverTarget = null;
72
+ dropTargets.length = 0;
73
+ }
74
+ };
75
+
76
+ // src/Draggable.ts
77
+ var Draggable = class {
78
+ el;
79
+ handle;
80
+ constrainTo;
81
+ axis;
82
+ snap;
83
+ useProxy;
84
+ groups;
85
+ disabled;
86
+ threshold;
87
+ userData;
88
+ onDragStartCb;
89
+ onDragCb;
90
+ onDragEndCb;
91
+ startX = 0;
92
+ startY = 0;
93
+ elStartX = 0;
94
+ elStartY = 0;
95
+ _dragging = false;
96
+ _started = false;
97
+ dragData = null;
98
+ moveHandler = null;
99
+ upHandler = null;
100
+ constructor(config) {
101
+ this.el = config.el;
102
+ this.handle = config.handle ?? null;
103
+ this.constrainTo = config.constrainTo ?? null;
104
+ this.axis = config.axis ?? null;
105
+ this.snap = config.snap ?? null;
106
+ this.useProxy = config.proxy ?? true;
107
+ this.groups = config.groups ?? [];
108
+ this.disabled = config.disabled ?? false;
109
+ this.threshold = config.threshold ?? 3;
110
+ this.userData = config.data ?? {};
111
+ this.onDragStartCb = config.onDragStart ?? null;
112
+ this.onDragCb = config.onDrag ?? null;
113
+ this.onDragEndCb = config.onDragEnd ?? null;
114
+ this.el.addEventListener("pointerdown", (e) => this.onPointerDown(e));
115
+ }
116
+ // -----------------------------------------------------------------------
117
+ // Pointer handlers
118
+ // -----------------------------------------------------------------------
119
+ onPointerDown(e) {
120
+ if (this.disabled) return;
121
+ if (this.handle) {
122
+ const target = e.target;
123
+ if (!target.closest(this.handle)) return;
124
+ }
125
+ e.preventDefault();
126
+ this.startX = e.clientX;
127
+ this.startY = e.clientY;
128
+ this.elStartX = parseInt(this.el.style.left || "0", 10);
129
+ this.elStartY = parseInt(this.el.style.top || "0", 10);
130
+ this._dragging = true;
131
+ this._started = false;
132
+ this.moveHandler = (me) => this.onPointerMove(me);
133
+ this.upHandler = (ue) => this.onPointerUp(ue);
134
+ document.addEventListener("pointermove", this.moveHandler);
135
+ document.addEventListener("pointerup", this.upHandler);
136
+ }
137
+ onPointerMove(e) {
138
+ if (!this._dragging) return;
139
+ const dx = e.clientX - this.startX;
140
+ const dy = e.clientY - this.startY;
141
+ if (!this._started) {
142
+ if (Math.abs(dx) < this.threshold && Math.abs(dy) < this.threshold) return;
143
+ this._started = true;
144
+ DragManager.setDragging(true);
145
+ this.dragData = {
146
+ source: this,
147
+ sourceEl: this.el,
148
+ groups: this.groups,
149
+ data: this.userData,
150
+ startX: this.startX,
151
+ startY: this.startY,
152
+ currentX: e.clientX,
153
+ currentY: e.clientY
154
+ };
155
+ this.onDragStartCb?.(this.dragData);
156
+ }
157
+ if (!this.dragData) return;
158
+ this.dragData.currentX = e.clientX;
159
+ this.dragData.currentY = e.clientY;
160
+ let newX = this.elStartX + dx;
161
+ let newY = this.elStartY + dy;
162
+ if (this.axis === "x") newY = this.elStartY;
163
+ if (this.axis === "y") newX = this.elStartX;
164
+ if (this.snap) {
165
+ newX = Math.round(newX / this.snap.x) * this.snap.x;
166
+ newY = Math.round(newY / this.snap.y) * this.snap.y;
167
+ }
168
+ if (this.constrainTo) {
169
+ const bounds = this.getConstrainBounds();
170
+ if (bounds) {
171
+ const elW = this.el.offsetWidth || parseInt(this.el.style.width || "0", 10);
172
+ const elH = this.el.offsetHeight || parseInt(this.el.style.height || "0", 10);
173
+ newX = Math.max(bounds.left, Math.min(newX, bounds.right - elW));
174
+ newY = Math.max(bounds.top, Math.min(newY, bounds.bottom - elH));
175
+ }
176
+ }
177
+ if (!this.useProxy) {
178
+ this.el.style.left = `${newX}px`;
179
+ this.el.style.top = `${newY}px`;
180
+ }
181
+ DragManager.notifyMove(this.dragData, e.clientX, e.clientY);
182
+ this.onDragCb?.(this.dragData);
183
+ }
184
+ onPointerUp(e) {
185
+ if (this.moveHandler) document.removeEventListener("pointermove", this.moveHandler);
186
+ if (this.upHandler) document.removeEventListener("pointerup", this.upHandler);
187
+ this.moveHandler = null;
188
+ this.upHandler = null;
189
+ if (this._started && this.dragData) {
190
+ DragManager.notifyDrop(this.dragData, e.clientX, e.clientY);
191
+ this.onDragEndCb?.(this.dragData);
192
+ }
193
+ this._dragging = false;
194
+ this._started = false;
195
+ this.dragData = null;
196
+ DragManager.setDragging(false);
197
+ }
198
+ // -----------------------------------------------------------------------
199
+ // Constraint bounds
200
+ // -----------------------------------------------------------------------
201
+ getConstrainBounds() {
202
+ if (this.constrainTo === "viewport") {
203
+ return { left: 0, top: 0, right: window.innerWidth, bottom: window.innerHeight };
204
+ }
205
+ if (this.constrainTo === "parent") {
206
+ const parent = this.el.parentElement;
207
+ if (!parent) return null;
208
+ const r = parent.getBoundingClientRect();
209
+ return { left: 0, top: 0, right: r.width, bottom: r.height };
210
+ }
211
+ if (this.constrainTo instanceof HTMLElement) {
212
+ const r = this.constrainTo.getBoundingClientRect();
213
+ return { left: r.left, top: r.top, right: r.right, bottom: r.bottom };
214
+ }
215
+ return null;
216
+ }
217
+ // -----------------------------------------------------------------------
218
+ // Public
219
+ // -----------------------------------------------------------------------
220
+ setDisabled(disabled) {
221
+ this.disabled = disabled;
222
+ }
223
+ destroy() {
224
+ if (this.moveHandler) document.removeEventListener("pointermove", this.moveHandler);
225
+ if (this.upHandler) document.removeEventListener("pointerup", this.upHandler);
226
+ }
227
+ };
228
+
229
+ // src/Droppable.ts
230
+ var Droppable = class {
231
+ el;
232
+ target;
233
+ constructor(config) {
234
+ this.el = config.el;
235
+ this.target = {
236
+ el: config.el,
237
+ accept: config.accept ?? [],
238
+ disabled: config.disabled ?? false,
239
+ overCls: config.overCls ?? "",
240
+ onDragEnter: config.onDragEnter,
241
+ onDragOver: config.onDragOver,
242
+ onDragLeave: config.onDragLeave,
243
+ onDrop: config.onDrop
244
+ };
245
+ DragManager.registerDropTarget(this.target);
246
+ }
247
+ setDisabled(disabled) {
248
+ this.target.disabled = disabled;
249
+ }
250
+ destroy() {
251
+ DragManager.unregisterDropTarget(this.target);
252
+ }
253
+ };
254
+
255
+ // src/DragProxy.ts
256
+ var DragProxy = class {
257
+ ghostEl = null;
258
+ ghostCls;
259
+ sourceEl;
260
+ constructor(config) {
261
+ this.sourceEl = config.sourceEl;
262
+ this.ghostCls = config.ghostCls ?? "x-dd-ghost";
263
+ }
264
+ show(x, y) {
265
+ if (this.ghostEl) this.hide();
266
+ this.ghostEl = document.createElement("div");
267
+ this.ghostEl.classList.add(this.ghostCls);
268
+ this.ghostEl.style.position = "fixed";
269
+ this.ghostEl.style.pointerEvents = "none";
270
+ this.ghostEl.style.zIndex = "99999";
271
+ this.ghostEl.style.opacity = "0.7";
272
+ this.ghostEl.style.left = `${x}px`;
273
+ this.ghostEl.style.top = `${y}px`;
274
+ const rect = this.sourceEl.getBoundingClientRect();
275
+ this.ghostEl.style.width = `${rect.width || 40}px`;
276
+ this.ghostEl.style.height = `${rect.height || 40}px`;
277
+ document.body.appendChild(this.ghostEl);
278
+ }
279
+ moveTo(x, y) {
280
+ if (!this.ghostEl) return;
281
+ this.ghostEl.style.left = `${x}px`;
282
+ this.ghostEl.style.top = `${y}px`;
283
+ }
284
+ setStatus(valid) {
285
+ if (!this.ghostEl) return;
286
+ this.ghostEl.classList.toggle("x-dd-drop-ok", valid);
287
+ this.ghostEl.classList.toggle("x-dd-drop-nodrop", !valid);
288
+ }
289
+ hide() {
290
+ if (this.ghostEl?.parentNode) {
291
+ this.ghostEl.parentNode.removeChild(this.ghostEl);
292
+ }
293
+ this.ghostEl = null;
294
+ }
295
+ getEl() {
296
+ return this.ghostEl;
297
+ }
298
+ };
299
+
300
+ // src/Sortable.ts
301
+ var Sortable = class {
302
+ el;
303
+ itemSelector;
304
+ onSortCb;
305
+ onStartCb;
306
+ onEndCb;
307
+ constructor(config) {
308
+ this.el = config.el;
309
+ this.itemSelector = config.itemSelector;
310
+ this.onSortCb = config.onSort ?? null;
311
+ this.onStartCb = config.onStart ?? null;
312
+ this.onEndCb = config.onEnd ?? null;
313
+ }
314
+ getItems() {
315
+ return Array.from(this.el.querySelectorAll(this.itemSelector));
316
+ }
317
+ getOrder() {
318
+ return this.getItems().map((el) => el.textContent ?? "");
319
+ }
320
+ moveItem(fromIndex, toIndex) {
321
+ const items = this.getItems();
322
+ if (fromIndex < 0 || fromIndex >= items.length) return;
323
+ if (toIndex < 0 || toIndex >= items.length) return;
324
+ if (fromIndex === toIndex) return;
325
+ this.onStartCb?.(fromIndex);
326
+ const item = items[fromIndex];
327
+ item.parentNode.removeChild(item);
328
+ const remaining = this.getItems();
329
+ if (toIndex >= remaining.length) {
330
+ this.el.appendChild(item);
331
+ } else {
332
+ this.el.insertBefore(item, remaining[toIndex]);
333
+ }
334
+ this.onSortCb?.(fromIndex, toIndex);
335
+ this.onEndCb?.(toIndex);
336
+ }
337
+ destroy() {
338
+ this.onSortCb = null;
339
+ this.onStartCb = null;
340
+ this.onEndCb = null;
341
+ }
342
+ };
343
+
344
+ // src/Resizable.ts
345
+ var HANDLE_CURSORS = {
346
+ n: "ns-resize",
347
+ s: "ns-resize",
348
+ e: "ew-resize",
349
+ w: "ew-resize",
350
+ ne: "nesw-resize",
351
+ sw: "nesw-resize",
352
+ nw: "nwse-resize",
353
+ se: "nwse-resize"
354
+ };
355
+ var Resizable = class {
356
+ el;
357
+ handles;
358
+ minW;
359
+ maxW;
360
+ minH;
361
+ maxH;
362
+ preserveRatio;
363
+ initialRatio;
364
+ onResizeCb;
365
+ onResizeStartCb;
366
+ onResizeEndCb;
367
+ handleEls = [];
368
+ constructor(config) {
369
+ this.el = config.el;
370
+ this.handles = config.handles.trim().split(/\s+/);
371
+ this.minW = config.minWidth ?? 20;
372
+ this.maxW = config.maxWidth ?? Infinity;
373
+ this.minH = config.minHeight ?? 20;
374
+ this.maxH = config.maxHeight ?? Infinity;
375
+ this.preserveRatio = config.preserveRatio ?? false;
376
+ this.onResizeCb = config.onResize ?? null;
377
+ this.onResizeStartCb = config.onResizeStart ?? null;
378
+ this.onResizeEndCb = config.onResizeEnd ?? null;
379
+ const w = parseInt(this.el.style.width || "100", 10);
380
+ const h = parseInt(this.el.style.height || "100", 10);
381
+ this.initialRatio = w / (h || 1);
382
+ this.createHandles();
383
+ }
384
+ // -----------------------------------------------------------------------
385
+ // Handle creation
386
+ // -----------------------------------------------------------------------
387
+ createHandles() {
388
+ const pos = getComputedStyle(this.el).position;
389
+ if (pos === "static" || pos === "") this.el.style.position = "relative";
390
+ for (const dir of this.handles) {
391
+ const handle = document.createElement("div");
392
+ handle.classList.add("x-resizable-handle", `x-resizable-handle-${dir}`);
393
+ handle.style.position = "absolute";
394
+ handle.style.zIndex = "100";
395
+ handle.style.cursor = HANDLE_CURSORS[dir] ?? "default";
396
+ this.positionHandle(handle, dir);
397
+ handle.addEventListener("pointerdown", (e) => this.onHandleDown(e, dir));
398
+ this.el.appendChild(handle);
399
+ this.handleEls.push(handle);
400
+ }
401
+ }
402
+ positionHandle(handle, dir) {
403
+ const size = "8px";
404
+ handle.style.width = size;
405
+ handle.style.height = size;
406
+ switch (dir) {
407
+ case "se":
408
+ handle.style.right = "0";
409
+ handle.style.bottom = "0";
410
+ break;
411
+ case "sw":
412
+ handle.style.left = "0";
413
+ handle.style.bottom = "0";
414
+ break;
415
+ case "ne":
416
+ handle.style.right = "0";
417
+ handle.style.top = "0";
418
+ break;
419
+ case "nw":
420
+ handle.style.left = "0";
421
+ handle.style.top = "0";
422
+ break;
423
+ case "e":
424
+ handle.style.right = "0";
425
+ handle.style.top = "50%";
426
+ handle.style.height = "100%";
427
+ handle.style.top = "0";
428
+ break;
429
+ case "w":
430
+ handle.style.left = "0";
431
+ handle.style.top = "0";
432
+ handle.style.height = "100%";
433
+ break;
434
+ case "s":
435
+ handle.style.bottom = "0";
436
+ handle.style.left = "0";
437
+ handle.style.width = "100%";
438
+ break;
439
+ case "n":
440
+ handle.style.top = "0";
441
+ handle.style.left = "0";
442
+ handle.style.width = "100%";
443
+ break;
444
+ }
445
+ }
446
+ // -----------------------------------------------------------------------
447
+ // Drag resize
448
+ // -----------------------------------------------------------------------
449
+ onHandleDown(e, dir) {
450
+ e.preventDefault();
451
+ e.stopPropagation();
452
+ const startX = e.clientX;
453
+ const startY = e.clientY;
454
+ const startW = parseInt(this.el.style.width || "100", 10);
455
+ const startH = parseInt(this.el.style.height || "100", 10);
456
+ const startLeft = parseInt(this.el.style.left || "0", 10);
457
+ const startTop = parseInt(this.el.style.top || "0", 10);
458
+ this.onResizeStartCb?.();
459
+ const onMove = (me) => {
460
+ const dx = me.clientX - startX;
461
+ const dy = me.clientY - startY;
462
+ let newW = startW;
463
+ let newH = startH;
464
+ let newLeft = startLeft;
465
+ let newTop = startTop;
466
+ if (dir.includes("e")) newW = startW + dx;
467
+ if (dir.includes("w")) {
468
+ newW = startW - dx;
469
+ newLeft = startLeft + dx;
470
+ }
471
+ if (dir.includes("s")) newH = startH + dy;
472
+ if (dir.includes("n")) {
473
+ newH = startH - dy;
474
+ newTop = startTop + dy;
475
+ }
476
+ if (this.preserveRatio) {
477
+ if (dir.includes("e") || dir.includes("w")) {
478
+ newH = newW / this.initialRatio;
479
+ } else {
480
+ newW = newH * this.initialRatio;
481
+ }
482
+ }
483
+ newW = Math.max(this.minW, Math.min(newW, this.maxW));
484
+ newH = Math.max(this.minH, Math.min(newH, this.maxH));
485
+ this.el.style.width = `${newW}px`;
486
+ this.el.style.height = `${newH}px`;
487
+ if (dir.includes("w")) this.el.style.left = `${newLeft}px`;
488
+ if (dir.includes("n")) this.el.style.top = `${newTop}px`;
489
+ this.onResizeCb?.(newW, newH);
490
+ };
491
+ const onUp = () => {
492
+ document.removeEventListener("pointermove", onMove);
493
+ document.removeEventListener("pointerup", onUp);
494
+ this.onResizeEndCb?.();
495
+ };
496
+ document.addEventListener("pointermove", onMove);
497
+ document.addEventListener("pointerup", onUp);
498
+ }
499
+ // -----------------------------------------------------------------------
500
+ // Public
501
+ // -----------------------------------------------------------------------
502
+ destroy() {
503
+ for (const handle of this.handleEls) {
504
+ handle.parentNode?.removeChild(handle);
505
+ }
506
+ this.handleEls = [];
507
+ }
508
+ };
509
+ export {
510
+ DragManager,
511
+ DragProxy,
512
+ Draggable,
513
+ Droppable,
514
+ Resizable,
515
+ Sortable
516
+ };
517
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/DragManager.ts","../src/Draggable.ts","../src/Droppable.ts","../src/DragProxy.ts","../src/Sortable.ts","../src/Resizable.ts"],"sourcesContent":["/**\n * @framesquared/dd – DragManager\n *\n * Singleton that manages all drag operations globally.\n * Tracks registered Droppables and coordinates hit-testing\n * during active drags.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { DragData } from './DragData.js';\n\nexport interface DropTarget {\n el: HTMLElement;\n accept: string[];\n disabled: boolean;\n overCls: string;\n onDragEnter?: (data: DragData) => boolean | void;\n onDragOver?: (data: DragData) => void;\n onDragLeave?: (data: DragData) => void;\n onDrop?: (data: DragData) => boolean | void;\n}\n\nlet dragging = false;\nconst dropTargets: DropTarget[] = [];\nlet currentOverTarget: DropTarget | null = null;\n\nfunction hitTest(target: DropTarget, x: number, y: number): boolean {\n const rect = target.el.getBoundingClientRect();\n return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;\n}\n\nfunction groupsMatch(dragGroups: string[], acceptGroups: string[]): boolean {\n if (acceptGroups.length === 0) return true;\n return dragGroups.some(g => acceptGroups.includes(g));\n}\n\nexport const DragManager = {\n isDragging(): boolean {\n return dragging;\n },\n\n setDragging(value: boolean): void {\n dragging = value;\n },\n\n registerDropTarget(target: DropTarget): void {\n if (!dropTargets.includes(target)) dropTargets.push(target);\n },\n\n unregisterDropTarget(target: DropTarget): void {\n const idx = dropTargets.indexOf(target);\n if (idx >= 0) dropTargets.splice(idx, 1);\n },\n\n /** Called during pointermove to check drop targets. */\n notifyMove(data: DragData, x: number, y: number): void {\n let overTarget: DropTarget | null = null;\n\n for (const target of dropTargets) {\n if (target.disabled) continue;\n if (!groupsMatch(data.groups, target.accept)) continue;\n if (hitTest(target, x, y)) {\n overTarget = target;\n break;\n }\n }\n\n // Leave previous target\n if (currentOverTarget && currentOverTarget !== overTarget) {\n if (currentOverTarget.overCls) {\n currentOverTarget.el.classList.remove(currentOverTarget.overCls);\n }\n currentOverTarget.onDragLeave?.(data);\n currentOverTarget = null;\n }\n\n // Enter new target\n if (overTarget && overTarget !== currentOverTarget) {\n currentOverTarget = overTarget;\n if (overTarget.overCls) {\n overTarget.el.classList.add(overTarget.overCls);\n }\n overTarget.onDragEnter?.(data);\n }\n\n // Over current target\n if (currentOverTarget) {\n currentOverTarget.onDragOver?.(data);\n }\n },\n\n /** Called on pointerup to finalize drop. */\n notifyDrop(data: DragData, _x: number, _y: number): boolean {\n let dropped = false;\n\n if (currentOverTarget) {\n if (currentOverTarget.overCls) {\n currentOverTarget.el.classList.remove(currentOverTarget.overCls);\n }\n currentOverTarget.onDrop?.(data);\n dropped = true;\n currentOverTarget = null;\n }\n\n return dropped;\n },\n\n reset(): void {\n dragging = false;\n currentOverTarget = null;\n dropTargets.length = 0;\n },\n};\n","/**\n * @framesquared/dd – Draggable\n *\n * Makes an element draggable. Supports drag handles, axis lock,\n * snap-to-grid, constraint, and proxy modes. Integrates with\n * DragManager for drop target detection.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { DragManager } from './DragManager.js';\nimport type { DragData } from './DragData.js';\n\nexport interface DraggableConfig {\n el: HTMLElement;\n handle?: string;\n constrainTo?: HTMLElement | 'parent' | 'viewport';\n axis?: 'x' | 'y';\n snap?: { x: number; y: number };\n proxy?: boolean;\n ghostCls?: string;\n groups?: string[];\n disabled?: boolean;\n threshold?: number;\n data?: Record<string, unknown>;\n onDragStart?: (data: DragData) => void;\n onDrag?: (data: DragData) => void;\n onDragEnd?: (data: DragData) => void;\n}\n\nexport class Draggable {\n readonly el: HTMLElement;\n private handle: string | null;\n private constrainTo: HTMLElement | 'parent' | 'viewport' | null;\n private axis: 'x' | 'y' | null;\n private snap: { x: number; y: number } | null;\n private useProxy: boolean;\n private groups: string[];\n private disabled: boolean;\n private threshold: number;\n private userData: Record<string, unknown>;\n\n private onDragStartCb: ((data: DragData) => void) | null;\n private onDragCb: ((data: DragData) => void) | null;\n private onDragEndCb: ((data: DragData) => void) | null;\n\n private startX = 0;\n private startY = 0;\n private elStartX = 0;\n private elStartY = 0;\n private _dragging = false;\n private _started = false;\n private dragData: DragData | null = null;\n\n private moveHandler: ((e: PointerEvent) => void) | null = null;\n private upHandler: ((e: PointerEvent) => void) | null = null;\n\n constructor(config: DraggableConfig) {\n this.el = config.el;\n this.handle = config.handle ?? null;\n this.constrainTo = config.constrainTo ?? null;\n this.axis = config.axis ?? null;\n this.snap = config.snap ?? null;\n this.useProxy = config.proxy ?? true;\n this.groups = config.groups ?? [];\n this.disabled = config.disabled ?? false;\n this.threshold = config.threshold ?? 3;\n this.userData = config.data ?? {};\n this.onDragStartCb = config.onDragStart ?? null;\n this.onDragCb = config.onDrag ?? null;\n this.onDragEndCb = config.onDragEnd ?? null;\n\n this.el.addEventListener('pointerdown', (e: PointerEvent) => this.onPointerDown(e));\n }\n\n // -----------------------------------------------------------------------\n // Pointer handlers\n // -----------------------------------------------------------------------\n\n private onPointerDown(e: PointerEvent): void {\n if (this.disabled) return;\n\n // Check handle\n if (this.handle) {\n const target = e.target as HTMLElement;\n if (!target.closest(this.handle)) return;\n }\n\n e.preventDefault();\n this.startX = e.clientX;\n this.startY = e.clientY;\n this.elStartX = parseInt(this.el.style.left || '0', 10);\n this.elStartY = parseInt(this.el.style.top || '0', 10);\n this._dragging = true;\n this._started = false;\n\n this.moveHandler = (me: PointerEvent) => this.onPointerMove(me);\n this.upHandler = (ue: PointerEvent) => this.onPointerUp(ue);\n document.addEventListener('pointermove', this.moveHandler);\n document.addEventListener('pointerup', this.upHandler);\n }\n\n private onPointerMove(e: PointerEvent): void {\n if (!this._dragging) return;\n\n const dx = e.clientX - this.startX;\n const dy = e.clientY - this.startY;\n\n // Check threshold\n if (!this._started) {\n if (Math.abs(dx) < this.threshold && Math.abs(dy) < this.threshold) return;\n this._started = true;\n DragManager.setDragging(true);\n\n this.dragData = {\n source: this,\n sourceEl: this.el,\n groups: this.groups,\n data: this.userData,\n startX: this.startX,\n startY: this.startY,\n currentX: e.clientX,\n currentY: e.clientY,\n };\n\n this.onDragStartCb?.(this.dragData);\n }\n\n if (!this.dragData) return;\n this.dragData.currentX = e.clientX;\n this.dragData.currentY = e.clientY;\n\n // Compute position\n let newX = this.elStartX + dx;\n let newY = this.elStartY + dy;\n\n // Axis lock\n if (this.axis === 'x') newY = this.elStartY;\n if (this.axis === 'y') newX = this.elStartX;\n\n // Snap\n if (this.snap) {\n newX = Math.round(newX / this.snap.x) * this.snap.x;\n newY = Math.round(newY / this.snap.y) * this.snap.y;\n }\n\n // Constrain\n if (this.constrainTo) {\n const bounds = this.getConstrainBounds();\n if (bounds) {\n const elW = this.el.offsetWidth || parseInt(this.el.style.width || '0', 10);\n const elH = this.el.offsetHeight || parseInt(this.el.style.height || '0', 10);\n newX = Math.max(bounds.left, Math.min(newX, bounds.right - elW));\n newY = Math.max(bounds.top, Math.min(newY, bounds.bottom - elH));\n }\n }\n\n // Apply position (direct move when proxy:false)\n if (!this.useProxy) {\n this.el.style.left = `${newX}px`;\n this.el.style.top = `${newY}px`;\n }\n\n // Notify DragManager for drop targets\n DragManager.notifyMove(this.dragData, e.clientX, e.clientY);\n\n this.onDragCb?.(this.dragData);\n }\n\n private onPointerUp(e: PointerEvent): void {\n if (this.moveHandler) document.removeEventListener('pointermove', this.moveHandler);\n if (this.upHandler) document.removeEventListener('pointerup', this.upHandler);\n this.moveHandler = null;\n this.upHandler = null;\n\n if (this._started && this.dragData) {\n DragManager.notifyDrop(this.dragData, e.clientX, e.clientY);\n this.onDragEndCb?.(this.dragData);\n }\n\n this._dragging = false;\n this._started = false;\n this.dragData = null;\n DragManager.setDragging(false);\n }\n\n // -----------------------------------------------------------------------\n // Constraint bounds\n // -----------------------------------------------------------------------\n\n private getConstrainBounds(): { left: number; top: number; right: number; bottom: number } | null {\n if (this.constrainTo === 'viewport') {\n return { left: 0, top: 0, right: window.innerWidth, bottom: window.innerHeight };\n }\n if (this.constrainTo === 'parent') {\n const parent = this.el.parentElement;\n if (!parent) return null;\n const r = parent.getBoundingClientRect();\n return { left: 0, top: 0, right: r.width, bottom: r.height };\n }\n if (this.constrainTo instanceof HTMLElement) {\n const r = this.constrainTo.getBoundingClientRect();\n return { left: r.left, top: r.top, right: r.right, bottom: r.bottom };\n }\n return null;\n }\n\n // -----------------------------------------------------------------------\n // Public\n // -----------------------------------------------------------------------\n\n setDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n destroy(): void {\n if (this.moveHandler) document.removeEventListener('pointermove', this.moveHandler);\n if (this.upHandler) document.removeEventListener('pointerup', this.upHandler);\n }\n}\n","/**\n * @framesquared/dd – Droppable\n *\n * Makes an element a drop target. Registers with DragManager\n * for hit testing during active drags.\n */\n\nimport { DragManager } from './DragManager.js';\nimport type { DragData } from './DragData.js';\nimport type { DropTarget } from './DragManager.js';\n\nexport interface DroppableConfig {\n el: HTMLElement;\n accept?: string[];\n overCls?: string;\n disabled?: boolean;\n onDragEnter?: (data: DragData) => boolean | void;\n onDragOver?: (data: DragData) => void;\n onDragLeave?: (data: DragData) => void;\n onDrop?: (data: DragData) => boolean | void;\n}\n\nexport class Droppable {\n readonly el: HTMLElement;\n private target: DropTarget;\n\n constructor(config: DroppableConfig) {\n this.el = config.el;\n this.target = {\n el: config.el,\n accept: config.accept ?? [],\n disabled: config.disabled ?? false,\n overCls: config.overCls ?? '',\n onDragEnter: config.onDragEnter,\n onDragOver: config.onDragOver,\n onDragLeave: config.onDragLeave,\n onDrop: config.onDrop,\n };\n DragManager.registerDropTarget(this.target);\n }\n\n setDisabled(disabled: boolean): void {\n this.target.disabled = disabled;\n }\n\n destroy(): void {\n DragManager.unregisterDropTarget(this.target);\n }\n}\n","/**\n * @framesquared/dd – DragProxy\n * Visual feedback during drag — a ghost element that follows the cursor.\n */\n\nexport interface DragProxyConfig {\n sourceEl: HTMLElement;\n ghostCls?: string;\n}\n\nexport class DragProxy {\n private ghostEl: HTMLElement | null = null;\n private ghostCls: string;\n private sourceEl: HTMLElement;\n\n constructor(config: DragProxyConfig) {\n this.sourceEl = config.sourceEl;\n this.ghostCls = config.ghostCls ?? 'x-dd-ghost';\n }\n\n show(x: number, y: number): void {\n if (this.ghostEl) this.hide();\n this.ghostEl = document.createElement('div');\n this.ghostEl.classList.add(this.ghostCls);\n this.ghostEl.style.position = 'fixed';\n this.ghostEl.style.pointerEvents = 'none';\n this.ghostEl.style.zIndex = '99999';\n this.ghostEl.style.opacity = '0.7';\n this.ghostEl.style.left = `${x}px`;\n this.ghostEl.style.top = `${y}px`;\n\n const rect = this.sourceEl.getBoundingClientRect();\n this.ghostEl.style.width = `${rect.width || 40}px`;\n this.ghostEl.style.height = `${rect.height || 40}px`;\n\n document.body.appendChild(this.ghostEl);\n }\n\n moveTo(x: number, y: number): void {\n if (!this.ghostEl) return;\n this.ghostEl.style.left = `${x}px`;\n this.ghostEl.style.top = `${y}px`;\n }\n\n setStatus(valid: boolean): void {\n if (!this.ghostEl) return;\n this.ghostEl.classList.toggle('x-dd-drop-ok', valid);\n this.ghostEl.classList.toggle('x-dd-drop-nodrop', !valid);\n }\n\n hide(): void {\n if (this.ghostEl?.parentNode) {\n this.ghostEl.parentNode.removeChild(this.ghostEl);\n }\n this.ghostEl = null;\n }\n\n getEl(): HTMLElement | null {\n return this.ghostEl;\n }\n}\n","/**\n * @framesquared/dd – Sortable\n *\n * Makes items within a container sortable by drag.\n * Provides moveItem() for programmatic reordering\n * and fires sort/start/end events.\n */\n\nexport interface SortableConfig {\n el: HTMLElement;\n itemSelector: string;\n handle?: string;\n axis?: 'x' | 'y';\n group?: string;\n ghostClass?: string;\n onSort?: (oldIndex: number, newIndex: number) => void;\n onStart?: (index: number) => void;\n onEnd?: (index: number) => void;\n}\n\nexport class Sortable {\n private el: HTMLElement;\n private itemSelector: string;\n private onSortCb: ((o: number, n: number) => void) | null;\n private onStartCb: ((i: number) => void) | null;\n private onEndCb: ((i: number) => void) | null;\n\n constructor(config: SortableConfig) {\n this.el = config.el;\n this.itemSelector = config.itemSelector;\n this.onSortCb = config.onSort ?? null;\n this.onStartCb = config.onStart ?? null;\n this.onEndCb = config.onEnd ?? null;\n }\n\n getItems(): HTMLElement[] {\n return Array.from(this.el.querySelectorAll(this.itemSelector));\n }\n\n getOrder(): string[] {\n return this.getItems().map(el => el.textContent ?? '');\n }\n\n moveItem(fromIndex: number, toIndex: number): void {\n const items = this.getItems();\n if (fromIndex < 0 || fromIndex >= items.length) return;\n if (toIndex < 0 || toIndex >= items.length) return;\n if (fromIndex === toIndex) return;\n\n this.onStartCb?.(fromIndex);\n\n const item = items[fromIndex];\n // Remove from current position\n item.parentNode!.removeChild(item);\n\n // Re-query after removal\n const remaining = this.getItems();\n if (toIndex >= remaining.length) {\n this.el.appendChild(item);\n } else {\n this.el.insertBefore(item, remaining[toIndex]);\n }\n\n this.onSortCb?.(fromIndex, toIndex);\n this.onEndCb?.(toIndex);\n }\n\n destroy(): void {\n this.onSortCb = null;\n this.onStartCb = null;\n this.onEndCb = null;\n }\n}\n","/**\n * @framesquared/dd – Resizable\n *\n * Makes an element resizable by adding drag handles on specified\n * edges/corners. Supports min/max constraints and aspect ratio\n * preservation.\n */\n\nexport interface ResizableConfig {\n el: HTMLElement;\n handles: string;\n minWidth?: number;\n maxWidth?: number;\n minHeight?: number;\n maxHeight?: number;\n preserveRatio?: boolean;\n onResize?: (width: number, height: number) => void;\n onResizeStart?: () => void;\n onResizeEnd?: () => void;\n}\n\ntype HandleDir = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';\n\nconst HANDLE_CURSORS: Record<string, string> = {\n n: 'ns-resize', s: 'ns-resize',\n e: 'ew-resize', w: 'ew-resize',\n ne: 'nesw-resize', sw: 'nesw-resize',\n nw: 'nwse-resize', se: 'nwse-resize',\n};\n\nexport class Resizable {\n private el: HTMLElement;\n private handles: HandleDir[];\n private minW: number;\n private maxW: number;\n private minH: number;\n private maxH: number;\n private preserveRatio: boolean;\n private initialRatio: number;\n private onResizeCb: ((w: number, h: number) => void) | null;\n private onResizeStartCb: (() => void) | null;\n private onResizeEndCb: (() => void) | null;\n private handleEls: HTMLElement[] = [];\n\n constructor(config: ResizableConfig) {\n this.el = config.el;\n this.handles = config.handles.trim().split(/\\s+/) as HandleDir[];\n this.minW = config.minWidth ?? 20;\n this.maxW = config.maxWidth ?? Infinity;\n this.minH = config.minHeight ?? 20;\n this.maxH = config.maxHeight ?? Infinity;\n this.preserveRatio = config.preserveRatio ?? false;\n this.onResizeCb = config.onResize ?? null;\n this.onResizeStartCb = config.onResizeStart ?? null;\n this.onResizeEndCb = config.onResizeEnd ?? null;\n\n const w = parseInt(this.el.style.width || '100', 10);\n const h = parseInt(this.el.style.height || '100', 10);\n this.initialRatio = w / (h || 1);\n\n this.createHandles();\n }\n\n // -----------------------------------------------------------------------\n // Handle creation\n // -----------------------------------------------------------------------\n\n private createHandles(): void {\n // Ensure el is positioned\n const pos = getComputedStyle(this.el).position;\n if (pos === 'static' || pos === '') this.el.style.position = 'relative';\n\n for (const dir of this.handles) {\n const handle = document.createElement('div');\n handle.classList.add('x-resizable-handle', `x-resizable-handle-${dir}`);\n handle.style.position = 'absolute';\n handle.style.zIndex = '100';\n handle.style.cursor = HANDLE_CURSORS[dir] ?? 'default';\n this.positionHandle(handle, dir);\n handle.addEventListener('pointerdown', (e) => this.onHandleDown(e, dir));\n this.el.appendChild(handle);\n this.handleEls.push(handle);\n }\n }\n\n private positionHandle(handle: HTMLElement, dir: string): void {\n const size = '8px';\n handle.style.width = size;\n handle.style.height = size;\n\n switch (dir) {\n case 'se': handle.style.right = '0'; handle.style.bottom = '0'; break;\n case 'sw': handle.style.left = '0'; handle.style.bottom = '0'; break;\n case 'ne': handle.style.right = '0'; handle.style.top = '0'; break;\n case 'nw': handle.style.left = '0'; handle.style.top = '0'; break;\n case 'e': handle.style.right = '0'; handle.style.top = '50%'; handle.style.height = '100%'; handle.style.top = '0'; break;\n case 'w': handle.style.left = '0'; handle.style.top = '0'; handle.style.height = '100%'; break;\n case 's': handle.style.bottom = '0'; handle.style.left = '0'; handle.style.width = '100%'; break;\n case 'n': handle.style.top = '0'; handle.style.left = '0'; handle.style.width = '100%'; break;\n }\n }\n\n // -----------------------------------------------------------------------\n // Drag resize\n // -----------------------------------------------------------------------\n\n private onHandleDown(e: PointerEvent, dir: HandleDir): void {\n e.preventDefault();\n e.stopPropagation();\n\n const startX = e.clientX;\n const startY = e.clientY;\n const startW = parseInt(this.el.style.width || '100', 10);\n const startH = parseInt(this.el.style.height || '100', 10);\n const startLeft = parseInt(this.el.style.left || '0', 10);\n const startTop = parseInt(this.el.style.top || '0', 10);\n\n this.onResizeStartCb?.();\n\n const onMove = (me: PointerEvent) => {\n const dx = me.clientX - startX;\n const dy = me.clientY - startY;\n\n let newW = startW;\n let newH = startH;\n let newLeft = startLeft;\n let newTop = startTop;\n\n // Compute new dimensions based on handle direction\n if (dir.includes('e')) newW = startW + dx;\n if (dir.includes('w')) { newW = startW - dx; newLeft = startLeft + dx; }\n if (dir.includes('s')) newH = startH + dy;\n if (dir.includes('n')) { newH = startH - dy; newTop = startTop + dy; }\n\n // Preserve ratio\n if (this.preserveRatio) {\n if (dir.includes('e') || dir.includes('w')) {\n newH = newW / this.initialRatio;\n } else {\n newW = newH * this.initialRatio;\n }\n }\n\n // Clamp\n newW = Math.max(this.minW, Math.min(newW, this.maxW));\n newH = Math.max(this.minH, Math.min(newH, this.maxH));\n\n // Apply\n this.el.style.width = `${newW}px`;\n this.el.style.height = `${newH}px`;\n if (dir.includes('w')) this.el.style.left = `${newLeft}px`;\n if (dir.includes('n')) this.el.style.top = `${newTop}px`;\n\n this.onResizeCb?.(newW, newH);\n };\n\n const onUp = () => {\n document.removeEventListener('pointermove', onMove);\n document.removeEventListener('pointerup', onUp);\n this.onResizeEndCb?.();\n };\n\n document.addEventListener('pointermove', onMove);\n document.addEventListener('pointerup', onUp);\n }\n\n // -----------------------------------------------------------------------\n // Public\n // -----------------------------------------------------------------------\n\n destroy(): void {\n for (const handle of this.handleEls) {\n handle.parentNode?.removeChild(handle);\n }\n this.handleEls = [];\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@framesquared/dd",
3
+ "version": "0.1.0",
4
+ "description": "Drag and drop",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "dependencies": {
18
+ "@framesquared/core": "0.1.0"
19
+ },
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "test": "vitest run",
23
+ "clean": "rm -rf dist",
24
+ "typecheck": "tsc --noEmit --project tsconfig.build.json"
25
+ }
26
+ }