@surdeddd/wmkit 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -5
- package/README.ru.md +18 -5
- package/dist/angular.cjs +52 -0
- package/dist/angular.cjs.map +1 -0
- package/dist/angular.d.cts +15 -0
- package/dist/angular.d.ts +15 -0
- package/dist/angular.js +47 -0
- package/dist/angular.js.map +1 -0
- package/dist/{binder-BY-saDUB.d.cts → binder-0Oku22Nc.d.ts} +14 -2
- package/dist/{binder-D9UEE1SM.d.ts → binder-Dq_AZRbo.d.cts} +14 -2
- package/dist/{chunk-KQCVZ2W7.cjs → chunk-B35DANTX.cjs} +303 -35
- package/dist/chunk-B35DANTX.cjs.map +1 -0
- package/dist/{chunk-2TVOEDRG.js → chunk-YCHJXSTC.js} +303 -36
- package/dist/chunk-YCHJXSTC.js.map +1 -0
- package/dist/index.cjs +19 -15
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/persist.d.cts +1 -1
- package/dist/persist.d.ts +1 -1
- package/dist/popout.d.cts +1 -1
- package/dist/popout.d.ts +1 -1
- package/dist/react.cjs +3 -3
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/solid.cjs +3 -3
- package/dist/solid.d.cts +2 -2
- package/dist/solid.d.ts +2 -2
- package/dist/solid.js +1 -1
- package/dist/svelte.cjs +3 -3
- package/dist/svelte.d.cts +2 -2
- package/dist/svelte.d.ts +2 -2
- package/dist/svelte.js +1 -1
- package/dist/themes/light.css +202 -0
- package/dist/themes/retro.css +152 -0
- package/dist/{types-Bkrq2djr.d.cts → types-DdCtDHgt.d.cts} +23 -1
- package/dist/{types-Bkrq2djr.d.ts → types-DdCtDHgt.d.ts} +23 -1
- package/dist/vue.cjs +3 -3
- package/dist/vue.d.cts +2 -2
- package/dist/vue.d.ts +2 -2
- package/dist/vue.js +1 -1
- package/package.json +34 -7
- package/dist/chunk-2TVOEDRG.js.map +0 -1
- package/dist/chunk-KQCVZ2W7.cjs.map +0 -1
|
@@ -99,6 +99,42 @@ function detectSnapZone(x, y, viewport, options = {}) {
|
|
|
99
99
|
}
|
|
100
100
|
return null;
|
|
101
101
|
}
|
|
102
|
+
function nearestEdge(low, high, targetLow, targetHigh) {
|
|
103
|
+
return [targetLow - low, targetHigh - low, targetLow - high, targetHigh - high];
|
|
104
|
+
}
|
|
105
|
+
function magnetize(bounds, targets, threshold) {
|
|
106
|
+
const result = { x: bounds.x, y: bounds.y, snappedX: false, snappedY: false };
|
|
107
|
+
if (threshold <= 0 || targets.length === 0) return result;
|
|
108
|
+
let bestX = threshold + 1;
|
|
109
|
+
let bestY = threshold + 1;
|
|
110
|
+
for (const target of targets) {
|
|
111
|
+
for (const delta of nearestEdge(
|
|
112
|
+
bounds.x,
|
|
113
|
+
bounds.x + bounds.width,
|
|
114
|
+
target.x,
|
|
115
|
+
target.x + target.width
|
|
116
|
+
)) {
|
|
117
|
+
if (Math.abs(delta) <= threshold && Math.abs(delta) < Math.abs(bestX)) bestX = delta;
|
|
118
|
+
}
|
|
119
|
+
for (const delta of nearestEdge(
|
|
120
|
+
bounds.y,
|
|
121
|
+
bounds.y + bounds.height,
|
|
122
|
+
target.y,
|
|
123
|
+
target.y + target.height
|
|
124
|
+
)) {
|
|
125
|
+
if (Math.abs(delta) <= threshold && Math.abs(delta) < Math.abs(bestY)) bestY = delta;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (Math.abs(bestX) <= threshold) {
|
|
129
|
+
result.x = bounds.x + bestX;
|
|
130
|
+
result.snappedX = true;
|
|
131
|
+
}
|
|
132
|
+
if (Math.abs(bestY) <= threshold) {
|
|
133
|
+
result.y = bounds.y + bestY;
|
|
134
|
+
result.snappedY = true;
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
102
138
|
|
|
103
139
|
// src/core/manager.ts
|
|
104
140
|
var LAYER_RANK = { normal: 0, floating: 1, modal: 2 };
|
|
@@ -122,6 +158,7 @@ function createWindowManager(options = {}) {
|
|
|
122
158
|
const cascadeOffset = options.cascadeOffset ?? 32;
|
|
123
159
|
const cascadeOrigin = options.cascadeOrigin ?? { x: 32, y: 32 };
|
|
124
160
|
const idPrefix = options.idPrefix ?? "wm";
|
|
161
|
+
const historyLimit = options.historyLimit ?? 50;
|
|
125
162
|
let windows = {};
|
|
126
163
|
let order = [];
|
|
127
164
|
let focusedId = null;
|
|
@@ -133,6 +170,13 @@ function createWindowManager(options = {}) {
|
|
|
133
170
|
let batchDepth = 0;
|
|
134
171
|
let batchDirty = false;
|
|
135
172
|
const pendingEvents = [];
|
|
173
|
+
const past = [];
|
|
174
|
+
let future = [];
|
|
175
|
+
let interactionDepth = 0;
|
|
176
|
+
let interactionRecorded = false;
|
|
177
|
+
let skipNextHistory = false;
|
|
178
|
+
let pendingHistory = null;
|
|
179
|
+
const layouts = /* @__PURE__ */ new Map();
|
|
136
180
|
function getState() {
|
|
137
181
|
if (!snapshot) {
|
|
138
182
|
snapshot = { windows, order, focusedId, viewport };
|
|
@@ -517,47 +561,164 @@ function createWindowManager(options = {}) {
|
|
|
517
561
|
function setViewport(next) {
|
|
518
562
|
if (next.width === viewport.width && next.height === viewport.height) return;
|
|
519
563
|
viewport = { ...next };
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
if (win.stage === "maximized") {
|
|
524
|
-
const updated = { ...win, bounds: fullBounds() };
|
|
525
|
-
setWindow(updated);
|
|
526
|
-
queueEvent(() => emitter.emit("resize", { window: updated }));
|
|
527
|
-
} else if (win.stage === "snapped" && win.snapZone) {
|
|
528
|
-
const updated = { ...win, bounds: zoneBounds(win.snapZone, viewport) };
|
|
529
|
-
setWindow(updated);
|
|
530
|
-
queueEvent(() => emitter.emit("resize", { window: updated }));
|
|
531
|
-
} else if (win.stage === "normal" && keepInViewport) {
|
|
532
|
-
const bounds = clampToViewport(win.bounds, viewport, minVisible);
|
|
533
|
-
if (!boundsEqual(bounds, win.bounds)) {
|
|
534
|
-
const updated = { ...win, bounds };
|
|
535
|
-
setWindow(updated);
|
|
536
|
-
queueEvent(() => emitter.emit("move", { window: updated }));
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
snapshot = null;
|
|
541
|
-
batchDirty = true;
|
|
542
|
-
});
|
|
564
|
+
reflowViewport();
|
|
565
|
+
snapshot = null;
|
|
566
|
+
batchDirty = true;
|
|
543
567
|
}
|
|
544
568
|
function minimized() {
|
|
545
569
|
return Object.values(windows).filter((win) => win.stage === "minimized").sort((a, b) => a.openedSeq - b.openedSeq);
|
|
546
570
|
}
|
|
571
|
+
function captureEntry() {
|
|
572
|
+
return { windows, order, focusedId };
|
|
573
|
+
}
|
|
574
|
+
function recordHistory() {
|
|
575
|
+
if (skipNextHistory) {
|
|
576
|
+
skipNextHistory = false;
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
if (historyLimit <= 0) return;
|
|
580
|
+
if (interactionDepth > 0) {
|
|
581
|
+
if (interactionRecorded) return;
|
|
582
|
+
interactionRecorded = true;
|
|
583
|
+
}
|
|
584
|
+
past.push(pendingHistory);
|
|
585
|
+
if (past.length > historyLimit) past.shift();
|
|
586
|
+
future = [];
|
|
587
|
+
}
|
|
547
588
|
function transact(run) {
|
|
589
|
+
if (batchDepth === 0) pendingHistory = captureEntry();
|
|
548
590
|
batchDepth += 1;
|
|
549
591
|
try {
|
|
550
592
|
return run();
|
|
551
593
|
} finally {
|
|
552
594
|
batchDepth -= 1;
|
|
553
|
-
if (batchDepth === 0
|
|
554
|
-
batchDirty
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
595
|
+
if (batchDepth === 0) {
|
|
596
|
+
if (batchDirty) {
|
|
597
|
+
batchDirty = false;
|
|
598
|
+
recordHistory();
|
|
599
|
+
snapshot = null;
|
|
600
|
+
flushEvents();
|
|
601
|
+
emitter.emit("change", { state: getState() });
|
|
602
|
+
}
|
|
603
|
+
pendingHistory = null;
|
|
558
604
|
}
|
|
559
605
|
}
|
|
560
606
|
}
|
|
607
|
+
function reflowViewport() {
|
|
608
|
+
for (const id of order) {
|
|
609
|
+
const win = windows[id];
|
|
610
|
+
if (win.stage === "maximized") {
|
|
611
|
+
const updated = { ...win, bounds: fullBounds() };
|
|
612
|
+
setWindow(updated);
|
|
613
|
+
queueEvent(() => emitter.emit("resize", { window: updated }));
|
|
614
|
+
} else if (win.stage === "snapped" && win.snapZone) {
|
|
615
|
+
const updated = { ...win, bounds: zoneBounds(win.snapZone, viewport) };
|
|
616
|
+
setWindow(updated);
|
|
617
|
+
queueEvent(() => emitter.emit("resize", { window: updated }));
|
|
618
|
+
} else if (win.stage === "normal" && keepInViewport) {
|
|
619
|
+
const bounds = clampToViewport(win.bounds, viewport, minVisible);
|
|
620
|
+
if (!boundsEqual(bounds, win.bounds)) {
|
|
621
|
+
const updated = { ...win, bounds };
|
|
622
|
+
setWindow(updated);
|
|
623
|
+
queueEvent(() => emitter.emit("move", { window: updated }));
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
function applyEntry(entry) {
|
|
629
|
+
windows = entry.windows;
|
|
630
|
+
order = [...entry.order];
|
|
631
|
+
focusedId = entry.focusedId;
|
|
632
|
+
reflowViewport();
|
|
633
|
+
commit();
|
|
634
|
+
}
|
|
635
|
+
function undo() {
|
|
636
|
+
const entry = past.pop();
|
|
637
|
+
if (!entry) return false;
|
|
638
|
+
future.push(captureEntry());
|
|
639
|
+
skipNextHistory = true;
|
|
640
|
+
applyEntry(entry);
|
|
641
|
+
return true;
|
|
642
|
+
}
|
|
643
|
+
function redo() {
|
|
644
|
+
const entry = future.pop();
|
|
645
|
+
if (!entry) return false;
|
|
646
|
+
past.push(captureEntry());
|
|
647
|
+
skipNextHistory = true;
|
|
648
|
+
applyEntry(entry);
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
651
|
+
function beginInteraction() {
|
|
652
|
+
interactionDepth += 1;
|
|
653
|
+
if (interactionDepth === 1) interactionRecorded = false;
|
|
654
|
+
}
|
|
655
|
+
function endInteraction() {
|
|
656
|
+
if (interactionDepth > 0) interactionDepth -= 1;
|
|
657
|
+
}
|
|
658
|
+
function clearHistory() {
|
|
659
|
+
past.length = 0;
|
|
660
|
+
future = [];
|
|
661
|
+
}
|
|
662
|
+
function saveLayout(name) {
|
|
663
|
+
const data = serialize();
|
|
664
|
+
layouts.set(name, structuredClone(data));
|
|
665
|
+
return data;
|
|
666
|
+
}
|
|
667
|
+
function loadLayout(name) {
|
|
668
|
+
const data = layouts.get(name);
|
|
669
|
+
if (!data) return false;
|
|
670
|
+
return hydrate(structuredClone(data));
|
|
671
|
+
}
|
|
672
|
+
function getLayout(name) {
|
|
673
|
+
const data = layouts.get(name);
|
|
674
|
+
return data ? structuredClone(data) : void 0;
|
|
675
|
+
}
|
|
676
|
+
function setLayout(name, data) {
|
|
677
|
+
if (!isValidSerialized(data)) return false;
|
|
678
|
+
layouts.set(name, structuredClone(data));
|
|
679
|
+
return true;
|
|
680
|
+
}
|
|
681
|
+
function deleteLayout(name) {
|
|
682
|
+
return layouts.delete(name);
|
|
683
|
+
}
|
|
684
|
+
function layoutNames() {
|
|
685
|
+
return [...layouts.keys()];
|
|
686
|
+
}
|
|
687
|
+
function arrange(mode) {
|
|
688
|
+
const ids = order.filter((id) => windows[id].stage !== "minimized");
|
|
689
|
+
if (ids.length === 0) return;
|
|
690
|
+
if (mode === "cascade") {
|
|
691
|
+
ids.forEach((id, index) => {
|
|
692
|
+
const win = windows[id];
|
|
693
|
+
const size = win.restoreBounds ?? win.bounds;
|
|
694
|
+
restoreTo(id, {
|
|
695
|
+
x: cascadeOrigin.x + index % 10 * cascadeOffset,
|
|
696
|
+
y: cascadeOrigin.y + index % 10 * cascadeOffset,
|
|
697
|
+
width: size.width,
|
|
698
|
+
height: size.height
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
const cols = Math.ceil(Math.sqrt(ids.length));
|
|
704
|
+
const rows = Math.ceil(ids.length / cols);
|
|
705
|
+
const cellWidth = Math.floor(viewport.width / cols);
|
|
706
|
+
const cellHeight = Math.floor(viewport.height / rows);
|
|
707
|
+
ids.forEach((id, index) => {
|
|
708
|
+
restoreTo(id, {
|
|
709
|
+
x: index % cols * cellWidth,
|
|
710
|
+
y: Math.floor(index / cols) * cellHeight,
|
|
711
|
+
width: cellWidth,
|
|
712
|
+
height: cellHeight
|
|
713
|
+
});
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
function minimizeAll() {
|
|
717
|
+
for (const id of [...order]) minimize(id);
|
|
718
|
+
}
|
|
719
|
+
function restoreAll() {
|
|
720
|
+
for (const win of minimized()) restore(win.id);
|
|
721
|
+
}
|
|
561
722
|
function serialize() {
|
|
562
723
|
return {
|
|
563
724
|
version: 1,
|
|
@@ -604,10 +765,16 @@ function createWindowManager(options = {}) {
|
|
|
604
765
|
const win = value;
|
|
605
766
|
return typeof win.id === "string" && win.id.length > 0 && isBounds(win.bounds) && STAGES.includes(win.stage) && LAYERS.includes(win.layer);
|
|
606
767
|
}
|
|
607
|
-
function
|
|
768
|
+
function isValidSerialized(data) {
|
|
608
769
|
if (typeof data !== "object" || data === null) return false;
|
|
609
770
|
if (data.version !== 1 || !Array.isArray(data.windows)) return false;
|
|
610
771
|
if (!data.windows.every(isSerializedWindow)) return false;
|
|
772
|
+
const ids = new Set(data.windows.map((win) => win.id));
|
|
773
|
+
return ids.size === data.windows.length;
|
|
774
|
+
}
|
|
775
|
+
function hydrate(data) {
|
|
776
|
+
if (!isValidSerialized(data)) return false;
|
|
777
|
+
const previousWindows = windows;
|
|
611
778
|
const nextWindows = {};
|
|
612
779
|
let maxSeq = 0;
|
|
613
780
|
for (const raw of data.windows) {
|
|
@@ -659,6 +826,21 @@ function createWindowManager(options = {}) {
|
|
|
659
826
|
const focusedWin = focusedId ? windows[focusedId] : null;
|
|
660
827
|
if (focusedWin?.layer !== "modal") focusedId = modal;
|
|
661
828
|
}
|
|
829
|
+
for (const id of Object.keys(previousWindows)) {
|
|
830
|
+
if (!windows[id]) {
|
|
831
|
+
const closed = previousWindows[id];
|
|
832
|
+
queueEvent(() => emitter.emit("close", { window: closed }));
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
for (const id of order) {
|
|
836
|
+
if (!previousWindows[id]) {
|
|
837
|
+
const opened = windows[id];
|
|
838
|
+
queueEvent(() => emitter.emit("open", { window: opened }));
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
queueEvent(() => emitter.emit("order", { order }));
|
|
842
|
+
clearHistory();
|
|
843
|
+
skipNextHistory = true;
|
|
662
844
|
commit();
|
|
663
845
|
return true;
|
|
664
846
|
}
|
|
@@ -689,6 +871,21 @@ function createWindowManager(options = {}) {
|
|
|
689
871
|
batch: (run) => transact(run),
|
|
690
872
|
serialize,
|
|
691
873
|
hydrate: (data) => transact(() => hydrate(data)),
|
|
874
|
+
undo: () => transact(undo),
|
|
875
|
+
redo: () => transact(redo),
|
|
876
|
+
canUndo: () => past.length > 0,
|
|
877
|
+
canRedo: () => future.length > 0,
|
|
878
|
+
beginInteraction,
|
|
879
|
+
endInteraction,
|
|
880
|
+
saveLayout,
|
|
881
|
+
loadLayout: (name) => transact(() => loadLayout(name)),
|
|
882
|
+
getLayout,
|
|
883
|
+
setLayout,
|
|
884
|
+
deleteLayout,
|
|
885
|
+
layoutNames,
|
|
886
|
+
arrange: (mode) => transact(() => arrange(mode)),
|
|
887
|
+
minimizeAll: () => transact(minimizeAll),
|
|
888
|
+
restoreAll: () => transact(restoreAll),
|
|
692
889
|
subscribe: (listener) => emitter.on("change", ({ state }) => listener(state)),
|
|
693
890
|
on: (event, listener) => emitter.on(event, listener),
|
|
694
891
|
destroy
|
|
@@ -699,6 +896,34 @@ function createWindowManager(options = {}) {
|
|
|
699
896
|
function prefersReducedMotion(win) {
|
|
700
897
|
return win.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
701
898
|
}
|
|
899
|
+
function flipFromTarget(source, target, options = {}) {
|
|
900
|
+
const view = source.ownerDocument.defaultView;
|
|
901
|
+
if (!view || prefersReducedMotion(view)) return;
|
|
902
|
+
if (typeof source.animate !== "function") return;
|
|
903
|
+
const from = target.getBoundingClientRect();
|
|
904
|
+
const to = source.getBoundingClientRect();
|
|
905
|
+
if (from.width === 0 || to.width === 0) return;
|
|
906
|
+
const ghost = source.ownerDocument.createElement("div");
|
|
907
|
+
const style = view.getComputedStyle(source);
|
|
908
|
+
ghost.style.cssText = `position:fixed;left:${to.left}px;top:${to.top}px;width:${to.width}px;height:${to.height}px;margin:0;pointer-events:none;z-index:2147483647;border-radius:${style.borderRadius};background:${style.backgroundColor};box-shadow:${style.boxShadow};transform-origin:top left;will-change:transform,opacity`;
|
|
909
|
+
source.ownerDocument.body.append(ghost);
|
|
910
|
+
const dx = from.left + from.width / 2 - (to.left + to.width / 2);
|
|
911
|
+
const dy = from.top + from.height / 2 - (to.top + to.height / 2);
|
|
912
|
+
const scaleX = Math.max(from.width / to.width, 0.05);
|
|
913
|
+
const scaleY = Math.max(from.height / to.height, 0.05);
|
|
914
|
+
const animation = ghost.animate(
|
|
915
|
+
[
|
|
916
|
+
{ transform: `translate(${dx}px, ${dy}px) scale(${scaleX}, ${scaleY})`, opacity: 0.2 },
|
|
917
|
+
{ transform: "translate(0, 0) scale(1, 1)", opacity: 0.9 }
|
|
918
|
+
],
|
|
919
|
+
{
|
|
920
|
+
duration: options.duration ?? 260,
|
|
921
|
+
easing: options.easing ?? "cubic-bezier(0.32, 0.72, 0, 1)"
|
|
922
|
+
}
|
|
923
|
+
);
|
|
924
|
+
animation.onfinish = () => ghost.remove();
|
|
925
|
+
animation.oncancel = () => ghost.remove();
|
|
926
|
+
}
|
|
702
927
|
function flipToTarget(source, target, options = {}) {
|
|
703
928
|
const view = source.ownerDocument.defaultView;
|
|
704
929
|
if (!view || prefersReducedMotion(view)) return;
|
|
@@ -841,7 +1066,27 @@ function createDragStarter(ctx) {
|
|
|
841
1066
|
}
|
|
842
1067
|
return;
|
|
843
1068
|
}
|
|
844
|
-
|
|
1069
|
+
let nextX = session.pendingX - session.grabDX;
|
|
1070
|
+
let nextY = session.pendingY - session.grabDY;
|
|
1071
|
+
if (ctx.magnetThreshold > 0) {
|
|
1072
|
+
const state = wm.getState();
|
|
1073
|
+
const targets = [
|
|
1074
|
+
{ x: 0, y: 0, width: state.viewport.width, height: state.viewport.height }
|
|
1075
|
+
];
|
|
1076
|
+
for (const otherId of state.order) {
|
|
1077
|
+
if (otherId === id) continue;
|
|
1078
|
+
const other = state.windows[otherId];
|
|
1079
|
+
if (other && other.stage !== "minimized") targets.push(other.bounds);
|
|
1080
|
+
}
|
|
1081
|
+
const magnet = magnetize(
|
|
1082
|
+
{ x: nextX, y: nextY, width: current.bounds.width, height: current.bounds.height },
|
|
1083
|
+
targets,
|
|
1084
|
+
ctx.magnetThreshold
|
|
1085
|
+
);
|
|
1086
|
+
nextX = magnet.x;
|
|
1087
|
+
nextY = magnet.y;
|
|
1088
|
+
}
|
|
1089
|
+
wm.move(id, nextX, nextY);
|
|
845
1090
|
if (ctx.snapEnabled && current.snappable) {
|
|
846
1091
|
const viewport = wm.getState().viewport;
|
|
847
1092
|
const rawZone = detectSnapZone(session.pendingX, session.pendingY, viewport, ctx.snapDetect);
|
|
@@ -921,14 +1166,17 @@ function createDragStarter(ctx) {
|
|
|
921
1166
|
wm.move(id, session.startBounds.x, session.startBounds.y);
|
|
922
1167
|
}
|
|
923
1168
|
}
|
|
1169
|
+
wm.endInteraction();
|
|
924
1170
|
return;
|
|
925
1171
|
}
|
|
926
1172
|
if (session.moved && session.zone) {
|
|
927
1173
|
if (session.zone === "maximize") wm.maximize(id);
|
|
928
1174
|
else wm.snap(id, session.zone);
|
|
929
1175
|
}
|
|
1176
|
+
wm.endInteraction();
|
|
930
1177
|
}
|
|
931
1178
|
session.finish = finish;
|
|
1179
|
+
wm.beginInteraction();
|
|
932
1180
|
ctx.claimDrag(session);
|
|
933
1181
|
handle.setPointerCapture(event.pointerId);
|
|
934
1182
|
handle.addEventListener("pointermove", onMove);
|
|
@@ -958,6 +1206,7 @@ function createResizeStarter(ctx) {
|
|
|
958
1206
|
event.preventDefault();
|
|
959
1207
|
event.stopPropagation();
|
|
960
1208
|
const handleEl = event.currentTarget;
|
|
1209
|
+
wm.beginInteraction();
|
|
961
1210
|
const releaseRect = ctx.trackRect();
|
|
962
1211
|
const startPoint = ctx.toLocal(event);
|
|
963
1212
|
const start = win.bounds;
|
|
@@ -1015,6 +1264,7 @@ function createResizeStarter(ctx) {
|
|
|
1015
1264
|
}
|
|
1016
1265
|
if (el) delete el.dataset.wmResizing;
|
|
1017
1266
|
if (cancelled) wm.resize(id, start);
|
|
1267
|
+
wm.endInteraction();
|
|
1018
1268
|
}
|
|
1019
1269
|
function onUp(upEvent) {
|
|
1020
1270
|
if (upEvent.pointerId !== event.pointerId) return;
|
|
@@ -1073,6 +1323,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1073
1323
|
const cycleEnabled = keyboardOptions.cycle !== false;
|
|
1074
1324
|
const hitEdge = options.hitAreas?.edge ?? (coarsePointer ? 16 : 8);
|
|
1075
1325
|
const hitCorner = options.hitAreas?.corner ?? (coarsePointer ? 24 : 12);
|
|
1326
|
+
const magnetThreshold = options.magnetism === false ? 0 : (typeof options.magnetism === "object" ? options.magnetism.threshold : void 0) ?? (coarsePointer ? 12 : 8);
|
|
1076
1327
|
element.dataset.wmDesktop = "";
|
|
1077
1328
|
if (view.getComputedStyle(element).position === "static") {
|
|
1078
1329
|
element.style.position = "relative";
|
|
@@ -1143,6 +1394,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1143
1394
|
topEdge,
|
|
1144
1395
|
hitEdge,
|
|
1145
1396
|
hitCorner,
|
|
1397
|
+
magnetThreshold,
|
|
1146
1398
|
currentDrag: () => drag,
|
|
1147
1399
|
claimDrag(session) {
|
|
1148
1400
|
drag = session;
|
|
@@ -1231,10 +1483,15 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1231
1483
|
);
|
|
1232
1484
|
cleanup.push(
|
|
1233
1485
|
wm.on("stage", ({ window: win, previous }) => {
|
|
1234
|
-
if (win.stage !== "minimized" || previous === "minimized") return;
|
|
1235
1486
|
const attached = registry.get(win.id);
|
|
1236
|
-
|
|
1237
|
-
if (
|
|
1487
|
+
if (!attached) return;
|
|
1488
|
+
if (win.stage === "minimized" && previous !== "minimized") {
|
|
1489
|
+
const target = options.minimizeTarget?.(win);
|
|
1490
|
+
if (target) flipToTarget(attached.element, target);
|
|
1491
|
+
} else if (previous === "minimized" && win.stage !== "minimized") {
|
|
1492
|
+
const target = options.minimizeTarget?.(win);
|
|
1493
|
+
if (target) flipFromTarget(attached.element, target);
|
|
1494
|
+
}
|
|
1238
1495
|
})
|
|
1239
1496
|
);
|
|
1240
1497
|
if (keyboardEnabled && cycleEnabled) {
|
|
@@ -1310,6 +1567,16 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1310
1567
|
};
|
|
1311
1568
|
handle.addEventListener("dblclick", onDoubleClick);
|
|
1312
1569
|
attached.cleanup.push(() => handle.removeEventListener("dblclick", onDoubleClick));
|
|
1570
|
+
if (options.onTitlebarContextMenu) {
|
|
1571
|
+
const onContextMenu = (event) => {
|
|
1572
|
+
const current = wm.get(id);
|
|
1573
|
+
if (!current) return;
|
|
1574
|
+
event.preventDefault();
|
|
1575
|
+
options.onTitlebarContextMenu?.(current, event);
|
|
1576
|
+
};
|
|
1577
|
+
handle.addEventListener("contextmenu", onContextMenu);
|
|
1578
|
+
attached.cleanup.push(() => handle.removeEventListener("contextmenu", onContextMenu));
|
|
1579
|
+
}
|
|
1313
1580
|
}
|
|
1314
1581
|
if (windowOptions.resizeHandles !== false) {
|
|
1315
1582
|
for (const { element: resizeHandle, direction } of createResizeHandles(
|
|
@@ -1464,7 +1731,8 @@ exports.createWindowManager = createWindowManager;
|
|
|
1464
1731
|
exports.defaultMessages = defaultMessages;
|
|
1465
1732
|
exports.detectSnapZone = detectSnapZone;
|
|
1466
1733
|
exports.flipToTarget = flipToTarget;
|
|
1734
|
+
exports.magnetize = magnetize;
|
|
1467
1735
|
exports.prefersReducedMotion = prefersReducedMotion;
|
|
1468
1736
|
exports.zoneBounds = zoneBounds;
|
|
1469
|
-
//# sourceMappingURL=chunk-
|
|
1470
|
-
//# sourceMappingURL=chunk-
|
|
1737
|
+
//# sourceMappingURL=chunk-B35DANTX.cjs.map
|
|
1738
|
+
//# sourceMappingURL=chunk-B35DANTX.cjs.map
|