@alekstar79/draggable-resizable-container 1.0.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.
@@ -0,0 +1,970 @@
1
+ import './index.css';var z = Object.defineProperty;
2
+ var S = (o, t, e) => t in o ? z(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e;
3
+ var a = (o, t, e) => S(o, typeof t != "symbol" ? t + "" : t, e);
4
+ import f, { reactive as b, computed as x, effect as p } from "@alekstar79/reactive-event-system";
5
+ import { clamp as m, deepMerge as M } from "@alekstar79/utility";
6
+ class R {
7
+ constructor(t) {
8
+ a(this, "container");
9
+ this.container = t || this.createContainer();
10
+ }
11
+ /**
12
+ * Create notifications container
13
+ */
14
+ createContainer() {
15
+ const t = document.querySelector(".notifications");
16
+ if (t)
17
+ return t;
18
+ const e = document.createElement("div");
19
+ return e.className = "notifications", document.body.appendChild(e), e;
20
+ }
21
+ /**
22
+ * Show notification toast
23
+ */
24
+ show(t, e = "info") {
25
+ const i = document.createElement("li"), s = this.removeToast.bind(this, i);
26
+ i.innerHTML = this.getToastHTML(t, e), i.className = `toast ${e}`, i.timeoutId = window.setTimeout(s, 4e3);
27
+ const r = i.querySelector(".icon");
28
+ r && r.addEventListener("click", s), this.container.appendChild(i);
29
+ }
30
+ /**
31
+ * Generate toast HTML based on type
32
+ */
33
+ getToastHTML(t, e) {
34
+ return `
35
+ <div class="column">
36
+ <i class="fa-solid ${{
37
+ success: "fa-circle-check",
38
+ error: "fa-circle-xmark",
39
+ warning: "fa-triangle-exclamation",
40
+ info: "fa-circle-info"
41
+ }[e]}"></i>
42
+ <span>${t}</span>
43
+ </div>
44
+ <i class="icon fa-solid fa-xmark"></i>
45
+ `;
46
+ }
47
+ /**
48
+ * Remove toast with animation
49
+ */
50
+ removeToast(t) {
51
+ t.classList.add("hide"), t.timeoutId && clearTimeout(t.timeoutId), setTimeout(() => {
52
+ t.parentNode && t.parentNode.removeChild(t);
53
+ }, 300);
54
+ }
55
+ /**
56
+ * Clear all notifications
57
+ */
58
+ clear() {
59
+ for (; this.container.firstChild; )
60
+ this.container.removeChild(this.container.firstChild);
61
+ }
62
+ }
63
+ new R();
64
+ class I {
65
+ /**
66
+ * Create container element with proper initialization
67
+ */
68
+ static createContainerElement(t, e, i, s, r) {
69
+ const n = document.createElement("div");
70
+ return n.className = "container advanced-container new", n.style.position = "absolute", n.style.width = `${t}px`, n.style.height = `${e}px`, i !== void 0 && (n.style.left = `${i}px`), s !== void 0 && (n.style.top = `${s}px`), r && (n.style.borderColor = r), n;
71
+ }
72
+ }
73
+ class k {
74
+ constructor(t) {
75
+ a(this, "templateLoader");
76
+ this.templateLoader = t;
77
+ }
78
+ /**
79
+ * Create content from various sources
80
+ * @param content - String, HTMLElement, or template name
81
+ * @param container - Container element to append content to
82
+ */
83
+ async createContent(t, e) {
84
+ try {
85
+ const i = e.classList.contains("container-content");
86
+ let s;
87
+ if (i ? s = e : (s = e.querySelector(".container-content"), s || (s = document.createElement("div"), s.className = "container-content", e.appendChild(s))), s.innerHTML = "", typeof t == "string")
88
+ s.innerHTML = t;
89
+ else if (t instanceof HTMLElement)
90
+ s.appendChild(t);
91
+ else if (t.template)
92
+ try {
93
+ s.innerHTML = await this.templateLoader.loadTemplate(t.template);
94
+ } catch (r) {
95
+ console.error(`[ContentCreator] Failed to load template: ${t.template}`, r), s.innerHTML = `<div class="template-error">Failed to load template: ${t.template}</div>`;
96
+ }
97
+ return s;
98
+ } catch (i) {
99
+ throw console.error("[ContentCreator] Error creating content:", i), i;
100
+ }
101
+ }
102
+ /**
103
+ * Set template loader instance
104
+ */
105
+ setTemplateLoader(t) {
106
+ this.templateLoader = t;
107
+ }
108
+ }
109
+ var T = Object.defineProperty, H = (o, t, e) => t in o ? T(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e, d = (o, t, e) => H(o, typeof t != "symbol" ? t + "" : t, e);
110
+ class C {
111
+ constructor() {
112
+ d(this, "templates", /* @__PURE__ */ new Map()), d(this, "lastUpdated", /* @__PURE__ */ new Map());
113
+ }
114
+ register(t) {
115
+ if (!t.name.trim()) throw new Error("Template name cannot be empty");
116
+ this.templates.set(t.name, t), this.lastUpdated.set(t.name, Date.now());
117
+ }
118
+ async registerBulk(t) {
119
+ for (const [e, i] of Object.entries(t)) this.register({ name: e, source: i });
120
+ }
121
+ get(t) {
122
+ return this.templates.get(t);
123
+ }
124
+ has(t) {
125
+ return this.templates.has(t);
126
+ }
127
+ remove(t) {
128
+ this.templates.delete(t), this.lastUpdated.delete(t);
129
+ }
130
+ list() {
131
+ return Array.from(this.templates.keys());
132
+ }
133
+ clear() {
134
+ this.templates.clear(), this.lastUpdated.clear();
135
+ }
136
+ getMetadata(t) {
137
+ var e;
138
+ return (e = this.templates.get(t)) == null ? void 0 : e.metadata;
139
+ }
140
+ }
141
+ class L {
142
+ constructor(t = 36e5) {
143
+ d(this, "cache", /* @__PURE__ */ new Map()), d(this, "ttl"), this.ttl = t;
144
+ }
145
+ set(t, e) {
146
+ this.cache.set(t, { content: e, timestamp: Date.now() });
147
+ }
148
+ get(t) {
149
+ const e = this.cache.get(t);
150
+ return e ? this.ttl <= 0 || Date.now() - e.timestamp > this.ttl ? (this.cache.delete(t), null) : e.content : null;
151
+ }
152
+ has(t) {
153
+ return this.get(t) !== null;
154
+ }
155
+ clear() {
156
+ this.cache.clear();
157
+ }
158
+ size() {
159
+ return this.cache.size;
160
+ }
161
+ }
162
+ class A {
163
+ constructor(t, e = {}) {
164
+ d(this, "cache"), d(this, "config"), d(this, "metrics"), d(this, "retryQueue", /* @__PURE__ */ new Map()), d(this, "registry"), this.registry = t ?? new C(), this.cache = new L(e == null ? void 0 : e.cacheTTL), this.config = this.normalizeConfig(e), this.metrics = { totalLoads: 0, totalHits: 0, totalMisses: 0, totalErrors: 0, averageLoadTime: 0, cacheHitRate: 0 };
165
+ }
166
+ normalizeConfig(t = {}) {
167
+ var i;
168
+ const e = t || {};
169
+ return { environment: e.environment === "auto" ? typeof process < "u" && ((i = process.env) == null ? void 0 : i.NODE_ENV) === "production" ? "production" : "development" : e.environment ?? "development", cache: e.cache ?? !0, cacheTTL: e.cacheTTL ?? 36e5, enableMetrics: e.enableMetrics ?? !0, onError: e.onError ?? (() => {
170
+ }), onWarn: e.onWarn ?? (() => {
171
+ }), fallbackTemplate: e.fallbackTemplate ?? '<div class="template-error">Template load failed</div>' };
172
+ }
173
+ async loadTemplate(t, e = 2) {
174
+ const i = performance.now(), s = this.retryQueue.get(t) ?? 0;
175
+ if (this.metrics.totalLoads++, this.config.cache) {
176
+ const n = this.cache.get(t);
177
+ if (n) return this.metrics.totalHits++, this.updateCacheHitRate(), n;
178
+ }
179
+ this.metrics.totalMisses++;
180
+ const r = this.registry.get(t);
181
+ if (!r) {
182
+ const n = this.createError(`Template "${t}" not found. Available: ${this.registry.list().join(", ")}`, t, s);
183
+ return this.metrics.totalErrors++, this.config.onError(n), this.config.fallbackTemplate;
184
+ }
185
+ try {
186
+ let n = typeof r.source == "function" ? await r.source() : r.source;
187
+ if (typeof n != "string") {
188
+ const h = this.createError("Template source must return a string, got " + typeof n, t, s);
189
+ return this.metrics.totalErrors++, this.config.onError(h), this.config.fallbackTemplate;
190
+ }
191
+ return this.config.cache && this.cache.set(t, n), this.retryQueue.delete(t), this.recordLoadTime(i), n;
192
+ } catch (n) {
193
+ const h = n instanceof Error ? n : new Error(String(n));
194
+ if (s < e) return this.retryQueue.set(t, s + 1), this.config.onWarn(`Retrying template "${t}" (attempt ${s + 1}/${e})`), await new Promise((u) => setTimeout(u, 100 * Math.pow(2, s))), this.loadTemplate(t, e);
195
+ const l = this.createError(`Failed to load template "${t}": ${h.message}`, t, s);
196
+ return this.metrics.totalErrors++, this.config.onError(l), this.retryQueue.delete(t), this.config.fallbackTemplate;
197
+ }
198
+ }
199
+ async loadTemplates(t) {
200
+ const e = {};
201
+ return await Promise.all(t.map(async (i) => {
202
+ e[i] = await this.loadTemplate(i);
203
+ })), e;
204
+ }
205
+ getMetrics() {
206
+ return { ...this.metrics };
207
+ }
208
+ clearCache() {
209
+ this.cache.clear();
210
+ }
211
+ resetMetrics() {
212
+ this.metrics = { totalLoads: 0, totalHits: 0, totalMisses: 0, totalErrors: 0, averageLoadTime: 0, cacheHitRate: 0 };
213
+ }
214
+ has(t) {
215
+ return this.registry.has(t);
216
+ }
217
+ list() {
218
+ return this.registry.list();
219
+ }
220
+ info(t) {
221
+ return this.registry.get(t);
222
+ }
223
+ createError(t, e, i) {
224
+ return Object.assign(new Error(t), { name: "TemplateLoadError", templateName: e, timestamp: /* @__PURE__ */ new Date(), retryCount: i });
225
+ }
226
+ recordLoadTime(t) {
227
+ if (this.config.enableMetrics) {
228
+ const e = performance.now() - t, i = this.metrics.averageLoadTime * (this.metrics.totalLoads - 1) + e;
229
+ this.metrics.averageLoadTime = i / this.metrics.totalLoads;
230
+ }
231
+ }
232
+ updateCacheHitRate() {
233
+ this.config.enableMetrics && (this.metrics.cacheHitRate = this.metrics.totalHits / this.metrics.totalLoads);
234
+ }
235
+ }
236
+ const c = class c {
237
+ constructor() {
238
+ a(this, "draggable", []);
239
+ }
240
+ zIndex(t) {
241
+ return `${c.highestZIndex + this.draggable.findIndex((e) => e === t)}`;
242
+ }
243
+ push(t) {
244
+ return this.draggable = [.../* @__PURE__ */ new Set([...this.draggable, t])], this;
245
+ }
246
+ remove(t) {
247
+ return this.draggable = this.draggable.filter((e) => e !== t), this;
248
+ }
249
+ sort(t) {
250
+ return this.draggable.sort((e, i) => e === t ? 1 : i === t ? -1 : 0), this;
251
+ }
252
+ };
253
+ a(c, "inatance"), a(c, "highestZIndex", 1e3), a(c, "init", () => c.inatance ?? (c.inatance = new c()));
254
+ let v = c;
255
+ function w() {
256
+ return {
257
+ width: window.innerWidth || document.documentElement.clientWidth,
258
+ height: window.innerHeight || document.documentElement.clientHeight
259
+ };
260
+ }
261
+ function D() {
262
+ return v.init();
263
+ }
264
+ const g = class g {
265
+ /**
266
+ * Create a new container manager instance with reactive state management
267
+ * @param container - HTML element to manage
268
+ * @param config - Configuration options
269
+ */
270
+ constructor(t, e = {}) {
271
+ // Streams for reactive event handling
272
+ a(this, "dragStream");
273
+ a(this, "resizeStream");
274
+ a(this, "stateChangeStream");
275
+ a(this, "eventEmitter");
276
+ a(this, "pluginEventEmitter");
277
+ a(this, "config");
278
+ a(this, "container");
279
+ a(this, "dragHandle");
280
+ a(this, "resizeHandles", /* @__PURE__ */ new Map());
281
+ a(this, "installedPlugins", /* @__PURE__ */ new Set());
282
+ a(this, "reactiveEffects", []);
283
+ a(this, "isDragging", !1);
284
+ a(this, "isResizing", !1);
285
+ a(this, "resizeDirection", null);
286
+ a(this, "startX", 0);
287
+ a(this, "startY", 0);
288
+ a(this, "startState");
289
+ a(this, "resizeObserver", null);
290
+ a(this, "parentResizeObserver", null);
291
+ a(this, "zIndexState");
292
+ a(this, "reactiveState", b({
293
+ x: 0,
294
+ y: 0,
295
+ width: 0,
296
+ height: 0,
297
+ mode: "smooth",
298
+ draggingDirection: "all"
299
+ }));
300
+ // Computed state with applied constraints
301
+ a(this, "constrainedState", x(() => {
302
+ var s;
303
+ const t = this.reactiveState;
304
+ if (!this.config) return { ...t };
305
+ let e = { ...t };
306
+ const { boundaries: i } = this.config;
307
+ if (e.width = m(
308
+ t.width,
309
+ i.minWidth || g.MINWIDTH,
310
+ i.maxWidth || 1 / 0
311
+ ), e.height = m(
312
+ t.height,
313
+ i.minHeight || g.MINHEIGHT,
314
+ i.maxHeight || 1 / 0
315
+ ), this.shouldConstrainToViewport()) {
316
+ const r = w();
317
+ e.x = m(t.x, 0, r.width - e.width), e.y = m(t.y, 0, r.height - e.height);
318
+ }
319
+ return (s = this.config) != null && s.constrainToParent && (e = this.constrainToParent(e)), e;
320
+ }));
321
+ // Automatic DOM updates with reactive effect
322
+ a(this, "domUpdateEffect", p(() => {
323
+ var e;
324
+ const t = this.constrainedState.value;
325
+ this.container && (this.container.style.left = `${t.x}px`, this.container.style.top = `${t.y}px`, this.container.style.width = `${t.width}px`, this.container.style.height = `${t.height}px`, (e = this.eventEmitter) == null || e.emit("stateChange", {
326
+ type: "stateChange",
327
+ state: { ...t },
328
+ mode: this.reactiveState.mode,
329
+ element: this.container
330
+ }));
331
+ }));
332
+ this.config = M({
333
+ _uid: "",
334
+ mode: "smooth",
335
+ constrainToViewport: !1,
336
+ draggingDirection: "all",
337
+ constrainToParent: !1,
338
+ boundaries: {
339
+ minWidth: g.MINWIDTH,
340
+ minHeight: g.MINHEIGHT
341
+ },
342
+ autoAdjust: {
343
+ enabled: !1,
344
+ width: !1,
345
+ height: !1
346
+ },
347
+ resize: {
348
+ enabled: !0,
349
+ directions: ["se"]
350
+ }
351
+ }, e), this.container = t, this.zIndexState = D();
352
+ const i = this.getCurrentState();
353
+ this.reactiveState.x = i.x, this.reactiveState.y = i.y, this.reactiveState.width = i.width, this.reactiveState.height = i.height, this.reactiveState.mode = this.config.mode, this.reactiveState.draggingDirection = this.config.draggingDirection, this.eventEmitter = new f({ enableMetrics: !0 }), this.pluginEventEmitter = new f({ enableMetrics: !0 }), this.stateChangeStream = this.eventEmitter.stream("stateChange"), this.dragStream = this.eventEmitter.stream("drag"), this.resizeStream = this.eventEmitter.stream("resize"), this.startState = this.getState(), this.setupEventMiddleware(), this.initializeHandles(), this.bindEvents(), this.setupResizeObservers(), this.setupReactiveMonitoring();
354
+ }
355
+ /**
356
+ * Set up ResizeObserver to track viewport and parent size changes
357
+ */
358
+ setupResizeObservers() {
359
+ var t;
360
+ this.shouldConstrainToViewport() && this.setupViewportResizeObserver(), (t = this.config.autoAdjust) != null && t.enabled && this.setupParentResizeObserver();
361
+ }
362
+ /**
363
+ * Determine if viewport constraints should be applied
364
+ */
365
+ shouldConstrainToViewport() {
366
+ return !this.config.constrainToParent || this.config.constrainToViewport;
367
+ }
368
+ /**
369
+ * Set up ResizeObserver to track viewport size changes
370
+ */
371
+ setupViewportResizeObserver() {
372
+ let t = null;
373
+ this.resizeObserver = new ResizeObserver(() => {
374
+ t && cancelAnimationFrame(t), t = requestAnimationFrame(() => {
375
+ this.handleViewportResize();
376
+ });
377
+ }), this.resizeObserver.observe(document.body);
378
+ }
379
+ /**
380
+ * Handle viewport resize event with reactive state updates
381
+ */
382
+ handleViewportResize() {
383
+ if (!this.shouldConstrainToViewport()) return;
384
+ const t = w(), i = { ...this.getState() };
385
+ let s = !1;
386
+ i.x + i.width > t.width && (i.x = Math.max(0, t.width - i.width), s = !0), i.y + i.height > t.height && (i.y = Math.max(0, t.height - i.height), s = !0), i.x < 0 && (i.x = 0, s = !0), i.y < 0 && (i.y = 0, s = !0), s && (this.setState(i), this.eventEmitter.emit("viewportResize", {
387
+ type: "viewportResize",
388
+ state: this.getState(),
389
+ mode: this.reactiveState.mode,
390
+ element: this.container
391
+ }));
392
+ }
393
+ /**
394
+ * Set up ResizeObserver for parent element auto-adjustment
395
+ */
396
+ setupParentResizeObserver() {
397
+ const t = this.container.parentElement;
398
+ t && (this.parentResizeObserver = new ResizeObserver((e) => {
399
+ for (const i of e)
400
+ this.handleParentResize(i);
401
+ }), this.parentResizeObserver.observe(t));
402
+ }
403
+ /**
404
+ * Handle parent element resize for auto-adjustment with reactive updates
405
+ */
406
+ handleParentResize(t) {
407
+ const { autoAdjust: e } = this.config;
408
+ if (!(e != null && e.enabled)) return;
409
+ const i = t.contentRect, r = { ...this.getState() };
410
+ let n = !1;
411
+ if (e.width) {
412
+ const h = this.getMaxWidthConstraint(), l = Math.min(i.width, h);
413
+ Math.abs(r.width - l) > 1 && (r.width = l, n = !0);
414
+ }
415
+ if (e.height) {
416
+ const h = this.getMaxHeightConstraint(), l = Math.min(i.height, h);
417
+ Math.abs(r.height - l) > 1 && (r.height = l, n = !0);
418
+ }
419
+ n && (this.setState(r), this.eventEmitter.emit("autoAdjust", {
420
+ type: "autoAdjust",
421
+ state: this.getState(),
422
+ mode: this.reactiveState.mode,
423
+ element: this.container
424
+ }));
425
+ }
426
+ /**
427
+ * Initialize drag and resize handles based on configuration
428
+ */
429
+ initializeHandles() {
430
+ var t;
431
+ this.initializeDragHandle(), (t = this.config.resize) != null && t.enabled && this.initializeResizeHandles();
432
+ }
433
+ /**
434
+ * Initialize drag handle
435
+ */
436
+ initializeDragHandle() {
437
+ this.dragHandle = this.container.querySelector("[data-drag-handle]"), this.dragHandle ? this.dragHandle.setAttribute("oncontextmenu", "return false") : (this.dragHandle = document.createElement("div"), this.dragHandle.className = "drag-handle", this.dragHandle.setAttribute("data-drag-handle", "true"), this.dragHandle.setAttribute("oncontextmenu", "return false"), this.container.prepend(this.dragHandle));
438
+ }
439
+ /**
440
+ * Initialize resize handles for all configured directions
441
+ */
442
+ initializeResizeHandles() {
443
+ var e;
444
+ (((e = this.config.resize) == null ? void 0 : e.directions) || ["se"]).forEach((i) => {
445
+ const s = this.createResizeHandle(i);
446
+ this.resizeHandles.set(i, s), this.container.appendChild(s);
447
+ });
448
+ }
449
+ /**
450
+ * Create individual resize handle for specific direction
451
+ */
452
+ createResizeHandle(t) {
453
+ const e = document.createElement("div");
454
+ return e.className = `resize-handle resize-${t}`, e.setAttribute("data-resize-handle", t), e.setAttribute("data-resize-direction", t), e.addEventListener("contextmenu", this.onContextMenu), this.applyResizeHandleStyles(e, t), e;
455
+ }
456
+ /**
457
+ * Apply styles and cursor for resize handle based on direction
458
+ */
459
+ applyResizeHandleStyles(t, e) {
460
+ const i = {
461
+ n: "ns-resize",
462
+ s: "ns-resize",
463
+ e: "ew-resize",
464
+ w: "ew-resize",
465
+ ne: "nesw-resize",
466
+ nw: "nwse-resize",
467
+ se: "nwse-resize",
468
+ sw: "nesw-resize"
469
+ };
470
+ t.style.position = "absolute", t.style.cursor = i[e], this.positionResizeHandle(t, e);
471
+ }
472
+ /**
473
+ * Position resize handle based on direction
474
+ */
475
+ positionResizeHandle(t, e) {
476
+ switch (e) {
477
+ case "n":
478
+ t.style.top = "0", t.style.left = "0", t.style.right = "0", t.style.height = "12px";
479
+ break;
480
+ case "s":
481
+ t.style.bottom = "0", t.style.left = "0", t.style.right = "0", t.style.height = "12px";
482
+ break;
483
+ case "e":
484
+ t.style.right = "0", t.style.top = "0", t.style.bottom = "0", t.style.width = "12px";
485
+ break;
486
+ case "w":
487
+ t.style.left = "0", t.style.top = "0", t.style.bottom = "0", t.style.width = "12px";
488
+ break;
489
+ case "ne":
490
+ t.style.top = "0", t.style.right = "0", t.style.width = "12px", t.style.height = "12px";
491
+ break;
492
+ case "nw":
493
+ t.style.top = "0", t.style.left = "0", t.style.width = "12px", t.style.height = "12px";
494
+ break;
495
+ case "se":
496
+ t.style.bottom = "0", t.style.right = "0", t.style.width = "12px", t.style.height = "12px";
497
+ break;
498
+ case "sw":
499
+ t.style.bottom = "0", t.style.left = "0", t.style.width = "12px", t.style.height = "12px";
500
+ break;
501
+ }
502
+ }
503
+ /**
504
+ * Bind event listeners to handles
505
+ */
506
+ bindEvents() {
507
+ var t;
508
+ this.onDragStart = this.onDragStart.bind(this), this.onDragMove = this.onDragMove.bind(this), this.onDragEnd = this.onDragEnd.bind(this), this.onResizeStart = this.onResizeStart.bind(this), this.onResizeMove = this.onResizeMove.bind(this), this.onResizeEnd = this.onResizeEnd.bind(this), this.onContextMenu = this.onContextMenu.bind(this), this.hasPluginByName("SnappingPlugin") || (this.dragHandle.addEventListener("mousedown", this.onDragStart), this.dragHandle.addEventListener("touchstart", this.onDragStart)), (t = this.config.resize) != null && t.enabled && this.resizeHandles.forEach((e, i) => {
509
+ e.addEventListener("mousedown", (s) => this.onResizeStart(s, i)), e.addEventListener("touchstart", (s) => this.onResizeStart(s, i));
510
+ }), this.dragHandle.addEventListener("contextmenu", this.onContextMenu);
511
+ }
512
+ /**
513
+ * Apply movement mode to coordinates
514
+ */
515
+ applyMovementMode(t, e) {
516
+ const i = { ...this.startState };
517
+ return this.reactiveState.mode === "smooth" && (i.x = this.startState.x + t, i.y = this.startState.y + e), i;
518
+ }
519
+ /**
520
+ * Calculate new state based on resize direction and deltas
521
+ */
522
+ calculateResizeState(t, e, i) {
523
+ const s = { ...this.startState };
524
+ switch (i) {
525
+ case "e":
526
+ s.width = this.startState.width + t;
527
+ break;
528
+ case "w":
529
+ s.width = this.startState.width - t, s.x = this.startState.x + t;
530
+ break;
531
+ case "n":
532
+ s.height = this.startState.height - e, s.y = this.startState.y + e;
533
+ break;
534
+ case "s":
535
+ s.height = this.startState.height + e;
536
+ break;
537
+ case "ne":
538
+ s.width = this.startState.width + t, s.height = this.startState.height - e, s.y = this.startState.y + e;
539
+ break;
540
+ case "nw":
541
+ s.width = this.startState.width - t, s.height = this.startState.height - e, s.x = this.startState.x + t, s.y = this.startState.y + e;
542
+ break;
543
+ case "se":
544
+ s.width = this.startState.width + t, s.height = this.startState.height + e;
545
+ break;
546
+ case "sw":
547
+ s.width = this.startState.width - t, s.height = this.startState.height + e, s.x = this.startState.x + t;
548
+ break;
549
+ }
550
+ return s;
551
+ }
552
+ /**
553
+ * Constrain container to parent element boundaries (both position and size)
554
+ */
555
+ constrainToParent(t) {
556
+ const e = this.container.parentElement;
557
+ if (!e) return t;
558
+ const i = e.getBoundingClientRect();
559
+ if (i.width === 0 || i.height === 0)
560
+ return t;
561
+ const s = Math.max(0, i.width - t.width), r = Math.max(0, i.height - t.height), n = i.width - t.x, h = i.height - t.y;
562
+ return {
563
+ x: m(t.x, 0, s),
564
+ y: m(t.y, 0, r),
565
+ width: m(t.width, 0, n),
566
+ height: m(t.height, 0, h)
567
+ };
568
+ }
569
+ /**
570
+ * Get maximum width constraint considering parent and boundaries
571
+ */
572
+ getMaxWidthConstraint() {
573
+ const { boundaries: t } = this.config;
574
+ let e = t.maxWidth || 1 / 0;
575
+ if (this.config.constrainToParent && this.container.parentElement) {
576
+ const i = this.container.parentElement.getBoundingClientRect().width;
577
+ e = Math.min(e, i);
578
+ }
579
+ return e;
580
+ }
581
+ /**
582
+ * Get maximum height constraint considering parent and boundaries
583
+ */
584
+ getMaxHeightConstraint() {
585
+ const { boundaries: t } = this.config;
586
+ let e = t.maxHeight || 1 / 0;
587
+ if (this.config.constrainToParent && this.container.parentElement) {
588
+ const i = this.container.parentElement.getBoundingClientRect().height;
589
+ e = Math.min(e, i);
590
+ }
591
+ return e;
592
+ }
593
+ /**
594
+ * Handle context menu event on drag handle
595
+ */
596
+ onContextMenu(t) {
597
+ t.preventDefault(), t.stopPropagation();
598
+ }
599
+ /**
600
+ * Check if snapping plugin is installed
601
+ */
602
+ hasPluginByName(t) {
603
+ return Array.from(this.installedPlugins).some((e) => e.constructor.name === t);
604
+ }
605
+ /**
606
+ * Get current container state from DOM
607
+ */
608
+ getCurrentState() {
609
+ const t = this.container.getBoundingClientRect(), e = window.getComputedStyle(this.container), i = parseFloat(e.width) || t.width, s = parseFloat(e.height) || t.height;
610
+ return {
611
+ x: t.left,
612
+ y: t.top,
613
+ width: i,
614
+ height: s
615
+ };
616
+ }
617
+ /**
618
+ * Setup event middleware for enhanced event processing
619
+ */
620
+ setupEventMiddleware() {
621
+ this.eventEmitter.use("*", (t, e) => (typeof window < "u" && window.DEBUG_CONTAINER_MANAGER && console.log(`[ContainerManager] ${e}:`, t), t)), this.eventEmitter.use("dragStart", (t, e) => {
622
+ if (this.reactiveState.mode === "pinned")
623
+ throw new Error("Cannot drag in pinned mode");
624
+ return t;
625
+ }), this.eventEmitter.use("drag", (t, e) => t);
626
+ }
627
+ /**
628
+ * Setup reactive monitoring for container metrics
629
+ */
630
+ setupReactiveMonitoring() {
631
+ const t = p(() => {
632
+ const { state: i } = this.stateChangeStream;
633
+ });
634
+ this.reactiveEffects.push(t);
635
+ const e = p(() => {
636
+ const i = this.eventEmitter.getMetrics();
637
+ i.state.errorCount > 10 && console.warn("[ContainerManager] High error count in event system:", i.state.errorCount);
638
+ });
639
+ this.reactiveEffects.push(e);
640
+ }
641
+ // Public API Implementation
642
+ /**
643
+ * Subscribe to container events
644
+ * @param event - Event name
645
+ * @param callback - Callback function
646
+ */
647
+ on(t, e) {
648
+ this.eventEmitter.on(t, e);
649
+ }
650
+ /**
651
+ * Unsubscribe from container events
652
+ * @param event - Event name
653
+ * @param callback - Callback function
654
+ */
655
+ off(t, e) {
656
+ this.eventEmitter.off(t, e);
657
+ }
658
+ /**
659
+ * Wait for specific container event
660
+ * @example
661
+ * // Wait for drag to complete
662
+ * const dragResult = await manager.waitFor('dragEnd')
663
+ * console.log('Drag completed:', dragResult.state)
664
+ */
665
+ waitFor(t, e) {
666
+ return this.eventEmitter.waitFor(t, e);
667
+ }
668
+ /**
669
+ * Get reactive stream for specific event type
670
+ * @example
671
+ * // Get state change stream
672
+ * const stateStream = manager.getStream('stateChange')
673
+ * stateStream.subscribe((data) => {
674
+ * console.log('State changed:', data.state)
675
+ * })
676
+ */
677
+ getStream(t) {
678
+ return this.eventEmitter.stream(t);
679
+ }
680
+ /**
681
+ * Pipe container events to another emitter
682
+ * @example
683
+ * // Pipe all events to analytics emitter
684
+ * manager.pipe('*', analyticsEmitter)
685
+ */
686
+ pipe(t, e, i) {
687
+ return this.eventEmitter.pipe(t, e, i);
688
+ }
689
+ /**
690
+ * Get event system metrics for monitoring
691
+ */
692
+ getEventMetrics() {
693
+ return this.eventEmitter.getMetrics();
694
+ }
695
+ /**
696
+ * Plugin-specific event emission
697
+ */
698
+ emitPluginEvent(t, e) {
699
+ this.pluginEventEmitter.emit(t, e);
700
+ }
701
+ /**
702
+ * Listen to plugin-specific events
703
+ */
704
+ onPluginEvent(t, e) {
705
+ this.pluginEventEmitter.on(t, e);
706
+ }
707
+ /**
708
+ * Remove plugin event listener
709
+ */
710
+ offPluginEvent(t, e) {
711
+ this.pluginEventEmitter.off(t, e);
712
+ }
713
+ /**
714
+ * Add middleware for plugin events
715
+ */
716
+ usePluginMiddleware(t, e) {
717
+ return this.pluginEventEmitter.use(t, e);
718
+ }
719
+ /**
720
+ * Handle drag start event
721
+ */
722
+ onDragStart(t) {
723
+ if (this.reactiveState.mode === "pinned") return;
724
+ t.preventDefault(), this.bringToFront(), this.isDragging = !0;
725
+ const e = t instanceof MouseEvent ? t.clientX : t.touches[0].clientX, i = t instanceof MouseEvent ? t.clientY : t.touches[0].clientY;
726
+ this.startX = e, this.startY = i, this.startState = this.getState(), this.eventEmitter.emit("dragStart", {
727
+ type: "drag",
728
+ state: this.getState(),
729
+ mode: this.reactiveState.mode,
730
+ element: this.container
731
+ }), document.addEventListener("mousemove", this.onDragMove), document.addEventListener("mouseup", this.onDragEnd), document.addEventListener("touchmove", this.onDragMove), document.addEventListener("touchend", this.onDragEnd);
732
+ }
733
+ /**
734
+ * Handle drag movement with reactive state updates
735
+ */
736
+ onDragMove(t) {
737
+ if (!this.isDragging) return;
738
+ const { clientX: e, clientY: i } = this.directionResolver(
739
+ t instanceof MouseEvent ? t.clientX : t.touches[0].clientX,
740
+ t instanceof MouseEvent ? t.clientY : t.touches[0].clientY
741
+ ), s = e - this.startX, r = i - this.startY, n = this.applyMovementMode(s, r);
742
+ this.setState(n), this.eventEmitter.emit("drag", {
743
+ type: "drag",
744
+ state: this.getState(),
745
+ mode: this.reactiveState.mode,
746
+ element: this.container
747
+ });
748
+ }
749
+ /**
750
+ * Handle drag end event
751
+ */
752
+ onDragEnd() {
753
+ this.isDragging = !1, document.removeEventListener("mousemove", this.onDragMove), document.removeEventListener("mouseup", this.onDragEnd), document.removeEventListener("touchmove", this.onDragMove), document.removeEventListener("touchend", this.onDragEnd), this.eventEmitter.emit("dragEnd", {
754
+ type: "drag",
755
+ state: this.getState(),
756
+ mode: this.reactiveState.mode,
757
+ element: this.container
758
+ });
759
+ }
760
+ /**
761
+ * Handle resize start event with direction
762
+ */
763
+ onResizeStart(t, e) {
764
+ t.preventDefault(), t.stopPropagation(), this.bringToFront(), this.isResizing = !0, this.resizeDirection = e;
765
+ const i = t instanceof MouseEvent ? t.clientX : t.touches[0].clientX, s = t instanceof MouseEvent ? t.clientY : t.touches[0].clientY;
766
+ this.startX = i, this.startY = s, this.startState = this.getState(), document.addEventListener("mousemove", this.onResizeMove), document.addEventListener("mouseup", this.onResizeEnd), document.addEventListener("touchmove", this.onResizeMove), document.addEventListener("touchend", this.onResizeEnd), this.eventEmitter.emit("resizeStart", {
767
+ type: "resize",
768
+ state: this.getState(),
769
+ mode: this.reactiveState.mode,
770
+ element: this.container,
771
+ direction: e
772
+ });
773
+ }
774
+ /**
775
+ * Handle resize movement with multi-direction support and reactive updates
776
+ */
777
+ onResizeMove(t) {
778
+ if (!this.isResizing || !this.resizeDirection) return;
779
+ const e = t instanceof MouseEvent ? t.clientX : t.touches[0].clientX, i = t instanceof MouseEvent ? t.clientY : t.touches[0].clientY, s = e - this.startX, r = i - this.startY, n = this.calculateResizeState(s, r, this.resizeDirection);
780
+ this.setState(n), this.eventEmitter.emit("resize", {
781
+ type: "resize",
782
+ state: this.getState(),
783
+ mode: this.reactiveState.mode,
784
+ direction: this.resizeDirection,
785
+ element: this.container
786
+ });
787
+ }
788
+ /**
789
+ * Handle resize end event
790
+ */
791
+ onResizeEnd() {
792
+ this.isResizing = !1, this.resizeDirection = null, document.removeEventListener("mousemove", this.onResizeMove), document.removeEventListener("mouseup", this.onResizeEnd), document.removeEventListener("touchmove", this.onResizeMove), document.removeEventListener("touchend", this.onResizeEnd), this.eventEmitter.emit("resizeEnd", {
793
+ type: "resize",
794
+ state: this.getState(),
795
+ mode: this.reactiveState.mode,
796
+ element: this.container
797
+ });
798
+ }
799
+ /**
800
+ * Set movement direction
801
+ */
802
+ setDirection(t) {
803
+ this.reactiveState.draggingDirection = t, this.emitPluginEvent("directionChanged", { direction: t });
804
+ }
805
+ /**
806
+ * Get current movement direction
807
+ */
808
+ getDirection() {
809
+ return this.reactiveState.draggingDirection;
810
+ }
811
+ /**
812
+ * Resolve coordinates based on current direction mode
813
+ */
814
+ directionResolver(t, e) {
815
+ const i = this.reactiveState.draggingDirection, s = i === "vertical", r = i === "horizontal";
816
+ return {
817
+ clientX: s ? this.startX : t,
818
+ clientY: r ? this.startY : e
819
+ };
820
+ }
821
+ /**
822
+ * Get current movement mode
823
+ */
824
+ getMode() {
825
+ return this.reactiveState.mode;
826
+ }
827
+ /**
828
+ * Set movement mode with reactive update
829
+ */
830
+ setMode(t) {
831
+ this.reactiveState.mode = t, this.eventEmitter.emit("modeChange", {
832
+ type: "modeChange",
833
+ state: this.getState(),
834
+ mode: this.reactiveState.mode,
835
+ element: this.container
836
+ });
837
+ }
838
+ /**
839
+ * Update container boundaries
840
+ */
841
+ setBoundaries(t) {
842
+ this.config.boundaries = { ...this.config.boundaries, ...t };
843
+ }
844
+ /**
845
+ * Get current container state (reactive)
846
+ */
847
+ getState() {
848
+ return {
849
+ x: this.reactiveState.x,
850
+ y: this.reactiveState.y,
851
+ width: this.reactiveState.width,
852
+ height: this.reactiveState.height
853
+ };
854
+ }
855
+ /**
856
+ * Update container position and size with reactive state
857
+ */
858
+ setState(t) {
859
+ t.height !== void 0 && (this.reactiveState.height = t.height), t.width !== void 0 && (this.reactiveState.width = t.width), t.x !== void 0 && (this.reactiveState.x = t.x), t.y !== void 0 && (this.reactiveState.y = t.y), this.applyStateToDOM();
860
+ }
861
+ /**
862
+ * Apply current state to DOM immediately for synchronization
863
+ */
864
+ applyStateToDOM() {
865
+ const t = this.getState();
866
+ this.container.style.left = `${t.x}px`, this.container.style.top = `${t.y}px`, this.container.style.width = `${t.width}px`, this.container.style.height = `${t.height}px`;
867
+ }
868
+ /**
869
+ * Bring container to front programmatically
870
+ */
871
+ bringToFront() {
872
+ const { _uid: t } = this.config;
873
+ this.container.style.zIndex = this.zIndexState.sort(t).zIndex(t);
874
+ }
875
+ /**
876
+ * Get container DOM element
877
+ */
878
+ getContainer() {
879
+ return this.container;
880
+ }
881
+ /**
882
+ * Update auto-adjust configuration
883
+ */
884
+ setAutoAdjust(t) {
885
+ var e;
886
+ this.config.autoAdjust = { ...this.config.autoAdjust, ...t }, this.parentResizeObserver && (this.parentResizeObserver.disconnect(), this.parentResizeObserver = null), (e = this.config.autoAdjust) != null && e.enabled && this.setupParentResizeObserver();
887
+ }
888
+ /**
889
+ * Update resize configuration
890
+ */
891
+ setResizeConfig(t) {
892
+ var e;
893
+ this.config.resize = { ...this.config.resize, ...t }, this.resizeHandles.forEach((i) => i.remove()), this.resizeHandles.clear(), (e = this.config.resize) != null && e.enabled && (this.initializeResizeHandles(), this.bindEvents());
894
+ }
895
+ /**
896
+ * Set constrain to parent configuration
897
+ */
898
+ setConstrainToParent(t) {
899
+ this.config.constrainToParent = t, this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.shouldConstrainToViewport() && this.setupViewportResizeObserver();
900
+ }
901
+ /**
902
+ * Set constrain to viewport configuration
903
+ */
904
+ setConstrainToViewport(t) {
905
+ this.config.constrainToViewport = t, this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.shouldConstrainToViewport() && this.setupViewportResizeObserver();
906
+ }
907
+ /**
908
+ * Recalculate container state relative to parent element
909
+ */
910
+ recalculateForParent() {
911
+ if (!this.config.constrainToParent || !this.container.parentElement)
912
+ return;
913
+ const t = this.container.parentElement.getBoundingClientRect(), e = this.getState();
914
+ if (t.width === 0 || t.height === 0)
915
+ return;
916
+ const i = e.width, s = e.height, r = Math.min(i, t.width), n = Math.min(s, t.height), h = e.x, l = e.y, u = Math.min(h, t.width - r), y = Math.min(l, t.height - n);
917
+ this.setState({
918
+ x: u,
919
+ y,
920
+ width: r,
921
+ height: n
922
+ }), this.eventEmitter.emit("parentRecalculated", {
923
+ type: "parentRecalculated",
924
+ state: this.getState(),
925
+ mode: this.reactiveState.mode,
926
+ element: this.container
927
+ });
928
+ }
929
+ /**
930
+ * Install plugin on this container manager instance
931
+ */
932
+ use(t, e) {
933
+ if (this.installedPlugins.has(t)) return this;
934
+ try {
935
+ t.install(this, e), this.installedPlugins.add(t);
936
+ } catch (i) {
937
+ console.error("[ContainerManager] Failed to install plugin:", i);
938
+ }
939
+ return this;
940
+ }
941
+ /**
942
+ * Check if plugin is installed on this instance
943
+ */
944
+ hasPlugin(t) {
945
+ return this.installedPlugins.has(t);
946
+ }
947
+ /**
948
+ * Get all installed plugins on this instance
949
+ */
950
+ getInstalledPlugins() {
951
+ return Array.from(this.installedPlugins);
952
+ }
953
+ /**
954
+ * Destroy container manager with proper cleanup
955
+ */
956
+ destroy() {
957
+ this.reactiveEffects.forEach((t) => t()), this.reactiveEffects = [], this.stateChangeStream.destroy(), this.dragStream.destroy(), this.resizeStream.destroy(), this.eventEmitter.destroy(), this.pluginEventEmitter.destroy(), this.domUpdateEffect(), this.dragHandle.removeEventListener("mousedown", this.onDragStart), this.dragHandle.removeEventListener("touchstart", this.onDragStart), this.dragHandle.removeEventListener("contextmenu", this.onContextMenu), this.resizeHandles.forEach((t, e) => {
958
+ t.removeEventListener("mousedown", (i) => this.onResizeStart(i, e)), t.removeEventListener("touchstart", (i) => this.onResizeStart(i, e));
959
+ }), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.parentResizeObserver && (this.parentResizeObserver.disconnect(), this.parentResizeObserver = null), this.installedPlugins.clear(), this.zIndexState.remove(this.config._uid);
960
+ }
961
+ };
962
+ a(g, "MINWIDTH", 200), a(g, "MINHEIGHT", 45);
963
+ let E = g;
964
+ export {
965
+ I as ContainerInitializer,
966
+ E as ContainerManager,
967
+ k as ContentCreator,
968
+ A as TemplateLoader
969
+ };
970
+ //# sourceMappingURL=index.es.js.map