@surdeddd/wmkit 0.4.1 → 0.5.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 +2 -1
- package/README.ru.md +2 -1
- package/dist/angular.cjs +3 -3
- package/dist/angular.d.cts +2 -2
- package/dist/angular.d.ts +2 -2
- package/dist/angular.js +1 -1
- package/dist/{binder-B2A2IZGh.d.ts → binder-Ca3GOfZX.d.ts} +5 -1
- package/dist/{binder-Dl07SXIM.d.cts → binder-EBroZTRw.d.cts} +5 -1
- package/dist/{chunk-OOEDFA7K.js → chunk-L43XBN44.js} +290 -28
- package/dist/chunk-L43XBN44.js.map +1 -0
- package/dist/{chunk-TJ6QOOJ2.cjs → chunk-RXAMUBUJ.cjs} +290 -28
- package/dist/chunk-RXAMUBUJ.cjs.map +1 -0
- package/dist/index.cjs +18 -18
- 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/{types-t6pyVYKN.d.cts → types-LP7Inhxx.d.cts} +18 -0
- package/dist/{types-t6pyVYKN.d.ts → types-LP7Inhxx.d.ts} +18 -0
- 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 +7 -7
- package/dist/chunk-OOEDFA7K.js.map +0 -1
- package/dist/chunk-TJ6QOOJ2.cjs.map +0 -1
|
@@ -199,6 +199,8 @@ function createWindowManager(options = {}) {
|
|
|
199
199
|
let focusedId = null;
|
|
200
200
|
let viewport = options.viewport ?? { width: 0, height: 0 };
|
|
201
201
|
let workspace = normalizeWorkspace(options.workspace, 0);
|
|
202
|
+
let activeTabs = {};
|
|
203
|
+
let groupCounter = 0;
|
|
202
204
|
let seq = 0;
|
|
203
205
|
let idCounter = 0;
|
|
204
206
|
let cascadeIndex = 0;
|
|
@@ -211,12 +213,13 @@ function createWindowManager(options = {}) {
|
|
|
211
213
|
let future = [];
|
|
212
214
|
let interactionDepth = 0;
|
|
213
215
|
let interactionRecorded = false;
|
|
216
|
+
let interactionMark = null;
|
|
214
217
|
let skipNextHistory = false;
|
|
215
218
|
let pendingHistory = null;
|
|
216
219
|
const layouts = /* @__PURE__ */ new Map();
|
|
217
220
|
function getState() {
|
|
218
221
|
if (!snapshot) {
|
|
219
|
-
snapshot = { windows, order, focusedId, viewport, workspace };
|
|
222
|
+
snapshot = { windows, order, focusedId, viewport, workspace, groups: buildGroups() };
|
|
220
223
|
}
|
|
221
224
|
return snapshot;
|
|
222
225
|
}
|
|
@@ -268,11 +271,54 @@ function createWindowManager(options = {}) {
|
|
|
268
271
|
function onActiveWorkspace(win) {
|
|
269
272
|
return win.workspace === workspace;
|
|
270
273
|
}
|
|
274
|
+
function membersOf(groupId) {
|
|
275
|
+
return order.filter((entry) => windows[entry].groupId === groupId);
|
|
276
|
+
}
|
|
277
|
+
function isVisibleTab(win) {
|
|
278
|
+
return win.groupId === null || activeTabs[win.groupId] === win.id;
|
|
279
|
+
}
|
|
280
|
+
function buildGroups() {
|
|
281
|
+
const result = {};
|
|
282
|
+
for (const [groupId, activeId] of Object.entries(activeTabs)) {
|
|
283
|
+
result[groupId] = { id: groupId, activeId, members: membersOf(groupId) };
|
|
284
|
+
}
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
function syncGroup(source) {
|
|
288
|
+
if (source.groupId === null) return;
|
|
289
|
+
for (const id of membersOf(source.groupId)) {
|
|
290
|
+
if (id === source.id) continue;
|
|
291
|
+
const member = windows[id];
|
|
292
|
+
if (boundsEqual(member.bounds, source.bounds) && member.stage === source.stage && member.snapZone === source.snapZone && member.layer === source.layer && member.workspace === source.workspace) {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
setWindow({
|
|
296
|
+
...member,
|
|
297
|
+
bounds: source.bounds,
|
|
298
|
+
stage: source.stage,
|
|
299
|
+
snapZone: source.snapZone,
|
|
300
|
+
restoreBounds: source.restoreBounds,
|
|
301
|
+
restoreStage: source.restoreStage,
|
|
302
|
+
layer: source.layer,
|
|
303
|
+
workspace: source.workspace
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function dissolveIfOrphaned(groupId) {
|
|
308
|
+
const members = membersOf(groupId);
|
|
309
|
+
if (members.length >= 2) return;
|
|
310
|
+
for (const id of members) {
|
|
311
|
+
setWindow({ ...windows[id], groupId: null });
|
|
312
|
+
}
|
|
313
|
+
const { [groupId]: _dropped, ...rest } = activeTabs;
|
|
314
|
+
activeTabs = rest;
|
|
315
|
+
}
|
|
271
316
|
function topModalId() {
|
|
272
317
|
for (let i = order.length - 1; i >= 0; i -= 1) {
|
|
273
318
|
const win = windows[order[i]];
|
|
274
|
-
if (win.layer === "modal" && win.stage !== "minimized" && onActiveWorkspace(win))
|
|
319
|
+
if (win.layer === "modal" && win.stage !== "minimized" && onActiveWorkspace(win) && isVisibleTab(win)) {
|
|
275
320
|
return win.id;
|
|
321
|
+
}
|
|
276
322
|
}
|
|
277
323
|
return null;
|
|
278
324
|
}
|
|
@@ -280,7 +326,7 @@ function createWindowManager(options = {}) {
|
|
|
280
326
|
const modal = topModalId();
|
|
281
327
|
return order.filter((id) => {
|
|
282
328
|
const win = windows[id];
|
|
283
|
-
if (win.stage === "minimized" || !onActiveWorkspace(win)) return false;
|
|
329
|
+
if (win.stage === "minimized" || !onActiveWorkspace(win) || !isVisibleTab(win)) return false;
|
|
284
330
|
if (modal && win.layer !== "modal") return false;
|
|
285
331
|
return true;
|
|
286
332
|
});
|
|
@@ -321,7 +367,13 @@ function createWindowManager(options = {}) {
|
|
|
321
367
|
width: init.width ?? defaultSize.width,
|
|
322
368
|
height: init.height ?? defaultSize.height
|
|
323
369
|
};
|
|
324
|
-
const size = aspectRatio === null ? clampSize(requested, minSize, maxSize) : applyAspect(
|
|
370
|
+
const size = aspectRatio === null ? clampSize(requested, minSize, maxSize) : applyAspect(
|
|
371
|
+
requested,
|
|
372
|
+
aspectRatio,
|
|
373
|
+
minSize,
|
|
374
|
+
maxSize,
|
|
375
|
+
init.width === void 0 && init.height !== void 0 ? "height" : "width"
|
|
376
|
+
);
|
|
325
377
|
const position = positionForOpen(init);
|
|
326
378
|
let bounds = { ...position, ...size };
|
|
327
379
|
if (keepInViewport) bounds = clampToViewport(bounds, viewport, minVisible);
|
|
@@ -337,6 +389,7 @@ function createWindowManager(options = {}) {
|
|
|
337
389
|
snapZone: null,
|
|
338
390
|
layer: init.layer ?? "normal",
|
|
339
391
|
workspace: normalizeWorkspace(init.workspace, workspace),
|
|
392
|
+
groupId: null,
|
|
340
393
|
minSize,
|
|
341
394
|
maxSize,
|
|
342
395
|
aspectRatio,
|
|
@@ -380,6 +433,13 @@ function createWindowManager(options = {}) {
|
|
|
380
433
|
const win = windows[id];
|
|
381
434
|
if (!win) return false;
|
|
382
435
|
removeWindow(id);
|
|
436
|
+
if (win.groupId !== null) {
|
|
437
|
+
const remaining = membersOf(win.groupId);
|
|
438
|
+
if (activeTabs[win.groupId] === id && remaining[0]) {
|
|
439
|
+
activeTabs = { ...activeTabs, [win.groupId]: remaining[0] };
|
|
440
|
+
}
|
|
441
|
+
dissolveIfOrphaned(win.groupId);
|
|
442
|
+
}
|
|
383
443
|
queueEvent(() => emitter.emit("close", { window: win }));
|
|
384
444
|
if (focusedId === id) {
|
|
385
445
|
focusTop();
|
|
@@ -396,6 +456,7 @@ function createWindowManager(options = {}) {
|
|
|
396
456
|
const win = windows[id];
|
|
397
457
|
if (!win) return false;
|
|
398
458
|
if (!onActiveWorkspace(win)) setWorkspace(win.workspace);
|
|
459
|
+
if (!isVisibleTab(win)) activateTab(id);
|
|
399
460
|
const modal = topModalId();
|
|
400
461
|
if (modal && modal !== id && win.layer !== "modal") {
|
|
401
462
|
const modalWin = windows[modal];
|
|
@@ -437,7 +498,13 @@ function createWindowManager(options = {}) {
|
|
|
437
498
|
}
|
|
438
499
|
function snapBounds(win, zone) {
|
|
439
500
|
const rect = zoneBounds(zone, viewport);
|
|
440
|
-
|
|
501
|
+
const byWidth = normalizeSize(rect, win);
|
|
502
|
+
const size = byWidth.height > rect.height ? normalizeSize(rect, win, "height") : byWidth;
|
|
503
|
+
return {
|
|
504
|
+
x: Math.max(0, Math.min(rect.x, viewport.width - size.width)),
|
|
505
|
+
y: Math.max(0, Math.min(rect.y, viewport.height - size.height)),
|
|
506
|
+
...size
|
|
507
|
+
};
|
|
441
508
|
}
|
|
442
509
|
function focusUnlessBlocked(id) {
|
|
443
510
|
const modal = topModalId();
|
|
@@ -449,6 +516,7 @@ function createWindowManager(options = {}) {
|
|
|
449
516
|
const next = build(win);
|
|
450
517
|
if (!next) return false;
|
|
451
518
|
setWindow(next);
|
|
519
|
+
syncGroup(next);
|
|
452
520
|
queueEvent(() => emitter.emit("stage", { window: next, previous: win.stage }));
|
|
453
521
|
commit();
|
|
454
522
|
return true;
|
|
@@ -558,6 +626,7 @@ function createWindowManager(options = {}) {
|
|
|
558
626
|
if (boundsEqual(bounds, win.bounds)) return true;
|
|
559
627
|
const next = { ...win, bounds };
|
|
560
628
|
setWindow(next);
|
|
629
|
+
syncGroup(next);
|
|
561
630
|
queueEvent(() => emitter.emit("move", { window: next }));
|
|
562
631
|
commit();
|
|
563
632
|
return true;
|
|
@@ -579,6 +648,7 @@ function createWindowManager(options = {}) {
|
|
|
579
648
|
if (boundsEqual(bounds, win.bounds) && !becameNormal) return true;
|
|
580
649
|
const next = becameNormal ? { ...win, stage: "normal", snapZone: null, restoreBounds: null, bounds } : { ...win, bounds };
|
|
581
650
|
setWindow(next);
|
|
651
|
+
syncGroup(next);
|
|
582
652
|
if (becameNormal) queueEvent(() => emitter.emit("stage", { window: next, previous: "snapped" }));
|
|
583
653
|
queueEvent(() => emitter.emit("resize", { window: next }));
|
|
584
654
|
commit();
|
|
@@ -602,10 +672,11 @@ function createWindowManager(options = {}) {
|
|
|
602
672
|
snappable: patch.snappable ?? win.snappable,
|
|
603
673
|
meta: patch.meta ? { ...win.meta, ...patch.meta } : win.meta
|
|
604
674
|
};
|
|
605
|
-
const size = normalizeSize(next.bounds, next);
|
|
675
|
+
const size = next.stage === "maximized" ? next.bounds : normalizeSize(next.bounds, next);
|
|
606
676
|
const resized = size.width !== next.bounds.width || size.height !== next.bounds.height;
|
|
607
677
|
const finalWin = resized ? { ...next, bounds: { ...next.bounds, ...size } } : next;
|
|
608
678
|
setWindow(finalWin);
|
|
679
|
+
syncGroup(finalWin);
|
|
609
680
|
if (patch.layer && patch.layer !== win.layer) {
|
|
610
681
|
order = sortByLayer(order);
|
|
611
682
|
queueEvent(() => emitter.emit("order", { order }));
|
|
@@ -647,14 +718,90 @@ function createWindowManager(options = {}) {
|
|
|
647
718
|
if (target === win.workspace) return false;
|
|
648
719
|
const updated = { ...win, workspace: target };
|
|
649
720
|
setWindow(updated);
|
|
721
|
+
syncGroup(updated);
|
|
650
722
|
if (!onActiveWorkspace(updated) && focusedId === id) {
|
|
651
723
|
focusTop();
|
|
652
724
|
if (focusedId) emitFocus(windows[focusedId], id);
|
|
725
|
+
} else if (onActiveWorkspace(updated) && topModalId() === id && focusedId !== id) {
|
|
726
|
+
const previous = focusedId;
|
|
727
|
+
focusedId = id;
|
|
728
|
+
emitFocus(updated, previous);
|
|
653
729
|
}
|
|
654
730
|
queueEvent(() => emitter.emit("update", { window: updated }));
|
|
655
731
|
commit();
|
|
656
732
|
return true;
|
|
657
733
|
}
|
|
734
|
+
function emitGroup(groupId, previous) {
|
|
735
|
+
const members = membersOf(groupId);
|
|
736
|
+
const activeId = activeTabs[groupId];
|
|
737
|
+
queueEvent(() => emitter.emit("group", { groupId, members, activeId, previous }));
|
|
738
|
+
}
|
|
739
|
+
function group(ids) {
|
|
740
|
+
const seeds = ids.filter((id, index) => windows[id] && ids.indexOf(id) === index);
|
|
741
|
+
const host = seeds[0] ? windows[seeds[0]] : null;
|
|
742
|
+
if (!host) return null;
|
|
743
|
+
const expanded = [];
|
|
744
|
+
for (const id of seeds) {
|
|
745
|
+
const win = windows[id];
|
|
746
|
+
const siblings = win.groupId === null ? [id] : membersOf(win.groupId);
|
|
747
|
+
for (const entry of siblings) if (!expanded.includes(entry)) expanded.push(entry);
|
|
748
|
+
}
|
|
749
|
+
if (expanded.length < 2) return null;
|
|
750
|
+
const groupId = `${idPrefix}-group-${++groupCounter}`;
|
|
751
|
+
const retired = /* @__PURE__ */ new Set();
|
|
752
|
+
for (const id of expanded) {
|
|
753
|
+
const win = windows[id];
|
|
754
|
+
if (win.groupId !== null) retired.add(win.groupId);
|
|
755
|
+
setWindow({
|
|
756
|
+
...win,
|
|
757
|
+
groupId,
|
|
758
|
+
bounds: host.bounds,
|
|
759
|
+
stage: host.stage,
|
|
760
|
+
snapZone: host.snapZone,
|
|
761
|
+
restoreBounds: host.restoreBounds,
|
|
762
|
+
restoreStage: host.restoreStage,
|
|
763
|
+
layer: host.layer,
|
|
764
|
+
workspace: host.workspace
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
const next = { ...activeTabs, [groupId]: host.id };
|
|
768
|
+
for (const old of retired) delete next[old];
|
|
769
|
+
activeTabs = next;
|
|
770
|
+
raise(host.id);
|
|
771
|
+
emitGroup(groupId, null);
|
|
772
|
+
queueEvent(() => emitter.emit("order", { order }));
|
|
773
|
+
commit();
|
|
774
|
+
if (onActiveWorkspace(host) && host.stage !== "minimized") focus(host.id);
|
|
775
|
+
return groupId;
|
|
776
|
+
}
|
|
777
|
+
function ungroup(id) {
|
|
778
|
+
const win = windows[id];
|
|
779
|
+
if (!win?.groupId) return false;
|
|
780
|
+
const groupId = win.groupId;
|
|
781
|
+
const wasActive = activeTabs[groupId] === id;
|
|
782
|
+
setWindow({ ...win, groupId: null });
|
|
783
|
+
const remaining = membersOf(groupId);
|
|
784
|
+
if (wasActive) activeTabs = { ...activeTabs, [groupId]: remaining[0] };
|
|
785
|
+
dissolveIfOrphaned(groupId);
|
|
786
|
+
if (membersOf(groupId).length >= 2) emitGroup(groupId, wasActive ? id : null);
|
|
787
|
+
commit();
|
|
788
|
+
focus(id);
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
791
|
+
function activateTab(id) {
|
|
792
|
+
const win = windows[id];
|
|
793
|
+
if (!win?.groupId) return false;
|
|
794
|
+
const groupId = win.groupId;
|
|
795
|
+
const previous = activeTabs[groupId];
|
|
796
|
+
if (previous === id) return false;
|
|
797
|
+
activeTabs = { ...activeTabs, [groupId]: id };
|
|
798
|
+
emitGroup(groupId, previous);
|
|
799
|
+
commit();
|
|
800
|
+
return true;
|
|
801
|
+
}
|
|
802
|
+
function groupMembers(groupId) {
|
|
803
|
+
return membersOf(groupId).map((id) => windows[id]);
|
|
804
|
+
}
|
|
658
805
|
function sendToBack(id) {
|
|
659
806
|
const win = windows[id];
|
|
660
807
|
if (!win) return false;
|
|
@@ -686,10 +833,10 @@ function createWindowManager(options = {}) {
|
|
|
686
833
|
);
|
|
687
834
|
}
|
|
688
835
|
function minimized() {
|
|
689
|
-
return Object.values(windows).filter((win) => win.stage === "minimized" && onActiveWorkspace(win)).sort((a, b) => a.openedSeq - b.openedSeq);
|
|
836
|
+
return Object.values(windows).filter((win) => win.stage === "minimized" && onActiveWorkspace(win) && isVisibleTab(win)).sort((a, b) => a.openedSeq - b.openedSeq);
|
|
690
837
|
}
|
|
691
838
|
function captureEntry() {
|
|
692
|
-
return { windows, order, focusedId, workspace };
|
|
839
|
+
return { windows, order, focusedId, workspace, activeTabs };
|
|
693
840
|
}
|
|
694
841
|
function recordHistory() {
|
|
695
842
|
if (!historyDirty) return;
|
|
@@ -751,6 +898,7 @@ function createWindowManager(options = {}) {
|
|
|
751
898
|
windows = entry.windows;
|
|
752
899
|
order = [...entry.order];
|
|
753
900
|
focusedId = entry.focusedId;
|
|
901
|
+
activeTabs = entry.activeTabs;
|
|
754
902
|
const previousWorkspace = workspace;
|
|
755
903
|
workspace = entry.workspace;
|
|
756
904
|
if (workspace !== previousWorkspace) {
|
|
@@ -777,14 +925,20 @@ function createWindowManager(options = {}) {
|
|
|
777
925
|
}
|
|
778
926
|
function beginInteraction() {
|
|
779
927
|
interactionDepth += 1;
|
|
780
|
-
if (interactionDepth === 1)
|
|
928
|
+
if (interactionDepth === 1) {
|
|
929
|
+
interactionRecorded = false;
|
|
930
|
+
interactionMark = { past: [...past], future };
|
|
931
|
+
}
|
|
781
932
|
}
|
|
782
933
|
function endInteraction() {
|
|
783
934
|
if (interactionDepth > 0) interactionDepth -= 1;
|
|
935
|
+
if (interactionDepth === 0) interactionMark = null;
|
|
784
936
|
}
|
|
785
937
|
function abortInteraction() {
|
|
786
|
-
if (interactionDepth > 0 &&
|
|
787
|
-
past.
|
|
938
|
+
if (interactionDepth > 0 && interactionMark) {
|
|
939
|
+
past.length = 0;
|
|
940
|
+
past.push(...interactionMark.past);
|
|
941
|
+
future = interactionMark.future;
|
|
788
942
|
interactionRecorded = false;
|
|
789
943
|
}
|
|
790
944
|
endInteraction();
|
|
@@ -875,7 +1029,8 @@ function createWindowManager(options = {}) {
|
|
|
875
1029
|
})),
|
|
876
1030
|
order: [...order],
|
|
877
1031
|
focusedId,
|
|
878
|
-
workspace
|
|
1032
|
+
workspace,
|
|
1033
|
+
activeTabs: { ...activeTabs }
|
|
879
1034
|
};
|
|
880
1035
|
}
|
|
881
1036
|
function isBounds(value) {
|
|
@@ -930,6 +1085,7 @@ function createWindowManager(options = {}) {
|
|
|
930
1085
|
snapZone: ZONES.includes(raw.snapZone) ? raw.snapZone : null,
|
|
931
1086
|
layer: raw.layer,
|
|
932
1087
|
workspace: normalizeWorkspace(raw.workspace, 0),
|
|
1088
|
+
groupId: typeof raw.groupId === "string" && raw.groupId.length > 0 ? raw.groupId : null,
|
|
933
1089
|
minSize: isSize(raw.minSize) ? { ...raw.minSize } : { width: 160, height: 100 },
|
|
934
1090
|
maxSize: readMaxSize(raw.maxSize),
|
|
935
1091
|
aspectRatio: typeof raw.aspectRatio === "number" && Number.isFinite(raw.aspectRatio) && raw.aspectRatio > 0 ? raw.aspectRatio : null,
|
|
@@ -971,7 +1127,18 @@ function createWindowManager(options = {}) {
|
|
|
971
1127
|
if (focusedCandidate && (focusedCandidate.stage === "minimized" || !onActiveWorkspace(focusedCandidate))) {
|
|
972
1128
|
focusedId = null;
|
|
973
1129
|
}
|
|
974
|
-
|
|
1130
|
+
const restoredTabs = {};
|
|
1131
|
+
const rawTabs = data.activeTabs;
|
|
1132
|
+
for (const id of order) {
|
|
1133
|
+
const groupId = windows[id].groupId;
|
|
1134
|
+
if (groupId === null || restoredTabs[groupId]) continue;
|
|
1135
|
+
const wanted = typeof rawTabs === "object" && rawTabs !== null ? rawTabs[groupId] : void 0;
|
|
1136
|
+
const members = membersOf(groupId);
|
|
1137
|
+
restoredTabs[groupId] = typeof wanted === "string" && members.includes(wanted) ? wanted : members[0];
|
|
1138
|
+
}
|
|
1139
|
+
activeTabs = restoredTabs;
|
|
1140
|
+
for (const groupId of Object.keys(restoredTabs)) dissolveIfOrphaned(groupId);
|
|
1141
|
+
if (!focusedId || !isVisibleTab(windows[focusedId])) focusTop();
|
|
975
1142
|
const modal = topModalId();
|
|
976
1143
|
if (modal) {
|
|
977
1144
|
const focusedWin = focusedId ? windows[focusedId] : null;
|
|
@@ -1025,6 +1192,10 @@ function createWindowManager(options = {}) {
|
|
|
1025
1192
|
workspace: () => workspace,
|
|
1026
1193
|
setWorkspace: (next) => transact(() => setWorkspace(next)),
|
|
1027
1194
|
moveToWorkspace: (id, next) => transact(() => moveToWorkspace(id, next)),
|
|
1195
|
+
group: (ids) => transact(() => group(ids)),
|
|
1196
|
+
ungroup: (id) => transact(() => ungroup(id)),
|
|
1197
|
+
activateTab: (id) => transact(() => activateTab(id)),
|
|
1198
|
+
groupMembers,
|
|
1028
1199
|
batch: (run) => transact(run),
|
|
1029
1200
|
serialize,
|
|
1030
1201
|
hydrate: (data) => transact(() => hydrate(data)),
|
|
@@ -1132,10 +1303,8 @@ function createAnnouncer(wm, container, messages = {}) {
|
|
|
1132
1303
|
element.style.cssText = "position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0";
|
|
1133
1304
|
container.append(element);
|
|
1134
1305
|
let clearTimer;
|
|
1135
|
-
let lastMessage = "";
|
|
1136
1306
|
let detailed = false;
|
|
1137
1307
|
function announce(message) {
|
|
1138
|
-
lastMessage = message;
|
|
1139
1308
|
element.textContent = message;
|
|
1140
1309
|
if (clearTimer !== void 0) clearTimeout(clearTimer);
|
|
1141
1310
|
clearTimer = setTimeout(() => {
|
|
@@ -1143,8 +1312,14 @@ function createAnnouncer(wm, container, messages = {}) {
|
|
|
1143
1312
|
}, 2e3);
|
|
1144
1313
|
}
|
|
1145
1314
|
const unsubscribers = [
|
|
1146
|
-
wm.on("open", ({ window: win }) =>
|
|
1147
|
-
|
|
1315
|
+
wm.on("open", ({ window: win }) => {
|
|
1316
|
+
announce(dict.opened(win.title));
|
|
1317
|
+
detailed = true;
|
|
1318
|
+
}),
|
|
1319
|
+
wm.on("close", ({ window: win }) => {
|
|
1320
|
+
announce(dict.closed(win.title));
|
|
1321
|
+
detailed = true;
|
|
1322
|
+
}),
|
|
1148
1323
|
wm.on("stage", ({ window: win, previous }) => {
|
|
1149
1324
|
if (win.stage === "minimized") announce(dict.minimized(win.title));
|
|
1150
1325
|
else if (win.stage === "maximized") announce(dict.maximized(win.title));
|
|
@@ -1155,7 +1330,7 @@ function createAnnouncer(wm, container, messages = {}) {
|
|
|
1155
1330
|
detailed = true;
|
|
1156
1331
|
}),
|
|
1157
1332
|
wm.on("focus", ({ window: win, previous }) => {
|
|
1158
|
-
if (detailed || previous === null
|
|
1333
|
+
if (detailed || previous === null) return;
|
|
1159
1334
|
announce(dict.focused(win.title));
|
|
1160
1335
|
}),
|
|
1161
1336
|
wm.on("workspace", ({ workspace }) => {
|
|
@@ -1210,6 +1385,11 @@ function createDragStarter(ctx) {
|
|
|
1210
1385
|
restored: win.stage === "normal",
|
|
1211
1386
|
moved: false,
|
|
1212
1387
|
zone: null,
|
|
1388
|
+
groupTarget: null,
|
|
1389
|
+
hoverId: null,
|
|
1390
|
+
hoverTimer: 0,
|
|
1391
|
+
clientX: event.clientX,
|
|
1392
|
+
clientY: event.clientY,
|
|
1213
1393
|
raf: 0,
|
|
1214
1394
|
pendingX: 0,
|
|
1215
1395
|
pendingY: 0,
|
|
@@ -1218,6 +1398,18 @@ function createDragStarter(ctx) {
|
|
|
1218
1398
|
}
|
|
1219
1399
|
};
|
|
1220
1400
|
const el = ctx.windowElement(id);
|
|
1401
|
+
function armGroup(target2) {
|
|
1402
|
+
session.groupTarget = target2;
|
|
1403
|
+
ctx.markGroupTarget(target2);
|
|
1404
|
+
}
|
|
1405
|
+
function clearHover() {
|
|
1406
|
+
if (session.hoverTimer !== 0) {
|
|
1407
|
+
view.clearTimeout(session.hoverTimer);
|
|
1408
|
+
session.hoverTimer = 0;
|
|
1409
|
+
}
|
|
1410
|
+
session.groupTarget = null;
|
|
1411
|
+
ctx.markGroupTarget(null);
|
|
1412
|
+
}
|
|
1221
1413
|
function flush() {
|
|
1222
1414
|
if (!session.hasPending || ctx.currentDrag() !== session) return;
|
|
1223
1415
|
session.hasPending = false;
|
|
@@ -1265,6 +1457,20 @@ function createDragStarter(ctx) {
|
|
|
1265
1457
|
nextY = magnet.y;
|
|
1266
1458
|
}
|
|
1267
1459
|
wm.move(id, nextX, nextY);
|
|
1460
|
+
const candidate = ctx.groupTarget(session.clientX, session.clientY, id);
|
|
1461
|
+
if (candidate !== session.hoverId) {
|
|
1462
|
+
session.hoverId = candidate;
|
|
1463
|
+
clearHover();
|
|
1464
|
+
if (candidate) {
|
|
1465
|
+
if (ctx.groupDwell <= 0) armGroup(candidate);
|
|
1466
|
+
else session.hoverTimer = view.setTimeout(() => armGroup(candidate), ctx.groupDwell);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
if (session.groupTarget) {
|
|
1470
|
+
session.zone = null;
|
|
1471
|
+
ctx.hidePreview();
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1268
1474
|
if (ctx.snapEnabled && current.snappable) {
|
|
1269
1475
|
const viewport = wm.getState().viewport;
|
|
1270
1476
|
const rawZone = detectSnapZone(session.pendingX, session.pendingY, viewport, ctx.snapDetect);
|
|
@@ -1297,6 +1503,8 @@ function createDragStarter(ctx) {
|
|
|
1297
1503
|
}
|
|
1298
1504
|
session.pendingX = movePoint.x;
|
|
1299
1505
|
session.pendingY = movePoint.y;
|
|
1506
|
+
session.clientX = moveEvent.clientX;
|
|
1507
|
+
session.clientY = moveEvent.clientY;
|
|
1300
1508
|
session.hasPending = true;
|
|
1301
1509
|
if (session.raf === 0) session.raf = view.requestAnimationFrame(flush);
|
|
1302
1510
|
}
|
|
@@ -1331,6 +1539,8 @@ function createDragStarter(ctx) {
|
|
|
1331
1539
|
wm.move(id, session.startBounds.x, session.startBounds.y);
|
|
1332
1540
|
}
|
|
1333
1541
|
}
|
|
1542
|
+
} else if (session.moved && session.groupTarget) {
|
|
1543
|
+
if (wm.group([session.groupTarget, id])) wm.activateTab(id);
|
|
1334
1544
|
} else if (session.moved && session.zone) {
|
|
1335
1545
|
if (session.zone === "maximize") wm.maximize(id);
|
|
1336
1546
|
else wm.snap(id, session.zone);
|
|
@@ -1350,6 +1560,8 @@ function createDragStarter(ctx) {
|
|
|
1350
1560
|
el.style.willChange = "";
|
|
1351
1561
|
}
|
|
1352
1562
|
ctx.hidePreview();
|
|
1563
|
+
if (session.hoverTimer !== 0) view.clearTimeout(session.hoverTimer);
|
|
1564
|
+
ctx.markGroupTarget(null);
|
|
1353
1565
|
if (cancelled) wm.abortInteraction();
|
|
1354
1566
|
else wm.endInteraction();
|
|
1355
1567
|
}
|
|
@@ -1402,6 +1614,7 @@ function createResizeStarter(ctx) {
|
|
|
1402
1614
|
let pendingX = 0;
|
|
1403
1615
|
let pendingY = 0;
|
|
1404
1616
|
let hasPending = false;
|
|
1617
|
+
let applied = false;
|
|
1405
1618
|
const el = ctx.windowElement(id);
|
|
1406
1619
|
if (el) el.dataset.wmResizing = direction;
|
|
1407
1620
|
function flush() {
|
|
@@ -1410,18 +1623,24 @@ function createResizeStarter(ctx) {
|
|
|
1410
1623
|
raf = 0;
|
|
1411
1624
|
const dx = pendingX - startPoint.x;
|
|
1412
1625
|
const dy = pendingY - startPoint.y;
|
|
1413
|
-
const
|
|
1626
|
+
const floor = Math.min(0, start.y);
|
|
1627
|
+
const top = direction.includes("n") ? Math.max(floor, start.y + dy) : start.y;
|
|
1414
1628
|
const raw = {
|
|
1415
1629
|
width: direction.includes("e") ? start.width + dx : direction.includes("w") ? start.width - dx : start.width,
|
|
1416
1630
|
height: direction.includes("s") ? start.height + dy : direction.includes("n") ? start.y + start.height - top : start.height
|
|
1417
1631
|
};
|
|
1418
|
-
|
|
1632
|
+
let size = aspect === null ? clampSize(raw, minSize, maxSize) : applyAspect(raw, aspect, minSize, maxSize, drive);
|
|
1633
|
+
const available = start.y + start.height - floor;
|
|
1634
|
+
if (direction.includes("n") && size.height > available) {
|
|
1635
|
+
size = applyAspect({ ...size, height: available }, aspect ?? 0, minSize, maxSize, "height");
|
|
1636
|
+
}
|
|
1419
1637
|
const next = {
|
|
1420
1638
|
x: direction.includes("w") ? start.x + start.width - size.width : start.x,
|
|
1421
1639
|
y: direction.includes("n") ? start.y + start.height - size.height : start.y,
|
|
1422
1640
|
...size
|
|
1423
1641
|
};
|
|
1424
1642
|
wm.resize(id, next);
|
|
1643
|
+
applied = true;
|
|
1425
1644
|
}
|
|
1426
1645
|
function onMove(moveEvent) {
|
|
1427
1646
|
if (moveEvent.pointerId !== event.pointerId) return;
|
|
@@ -1436,7 +1655,7 @@ function createResizeStarter(ctx) {
|
|
|
1436
1655
|
try {
|
|
1437
1656
|
if (raf !== 0) view.cancelAnimationFrame(raf);
|
|
1438
1657
|
if (hasPending && !cancelled) flush();
|
|
1439
|
-
if (cancelled) {
|
|
1658
|
+
if (cancelled && applied) {
|
|
1440
1659
|
if (startStage === "snapped" && startZone) {
|
|
1441
1660
|
wm.restoreTo(id, startRestore ?? start);
|
|
1442
1661
|
wm.snap(id, startZone);
|
|
@@ -1512,6 +1731,8 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1512
1731
|
const doc = element.ownerDocument;
|
|
1513
1732
|
const view = windowOf(element);
|
|
1514
1733
|
const coarsePointer = typeof view.matchMedia === "function" && view.matchMedia("(pointer: coarse)").matches;
|
|
1734
|
+
const groupingEnabled = options.grouping !== false;
|
|
1735
|
+
const groupDwell = (typeof options.grouping === "object" ? options.grouping.dwell : void 0) ?? 420;
|
|
1515
1736
|
const snapEnabled = options.snap !== false;
|
|
1516
1737
|
const snapOptions = typeof options.snap === "object" ? options.snap : {};
|
|
1517
1738
|
const snapPreviewEnabled = snapOptions.preview !== false;
|
|
@@ -1535,6 +1756,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1535
1756
|
let lastOrder = null;
|
|
1536
1757
|
let lastFocused = null;
|
|
1537
1758
|
let drag = null;
|
|
1759
|
+
let groupTargetId = null;
|
|
1538
1760
|
let cachedRect = null;
|
|
1539
1761
|
let rectUsers = 0;
|
|
1540
1762
|
let announcer = null;
|
|
@@ -1606,6 +1828,29 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1606
1828
|
hitEdge,
|
|
1607
1829
|
hitCorner,
|
|
1608
1830
|
magnetThreshold,
|
|
1831
|
+
groupDwell,
|
|
1832
|
+
groupTarget(clientX, clientY, selfId) {
|
|
1833
|
+
if (!groupingEnabled || typeof doc.elementsFromPoint !== "function") return null;
|
|
1834
|
+
for (const node of doc.elementsFromPoint(clientX, clientY)) {
|
|
1835
|
+
const handle = node.closest?.("[data-wm-drag]");
|
|
1836
|
+
const host = handle?.closest("[data-wm-window]");
|
|
1837
|
+
const id = host?.dataset.wmWindow;
|
|
1838
|
+
if (id && id !== selfId && registry.has(id)) return id;
|
|
1839
|
+
}
|
|
1840
|
+
return null;
|
|
1841
|
+
},
|
|
1842
|
+
markGroupTarget(id) {
|
|
1843
|
+
if (groupTargetId === id) return;
|
|
1844
|
+
if (groupTargetId) {
|
|
1845
|
+
const previous = registry.get(groupTargetId);
|
|
1846
|
+
if (previous) delete previous.element.dataset.wmTabTarget;
|
|
1847
|
+
}
|
|
1848
|
+
groupTargetId = id;
|
|
1849
|
+
if (id) {
|
|
1850
|
+
const next = registry.get(id);
|
|
1851
|
+
if (next) next.element.dataset.wmTabTarget = "";
|
|
1852
|
+
}
|
|
1853
|
+
},
|
|
1609
1854
|
currentDrag: () => drag,
|
|
1610
1855
|
claimDrag(session) {
|
|
1611
1856
|
drag = session;
|
|
@@ -1623,21 +1868,33 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1623
1868
|
observer.observe(element);
|
|
1624
1869
|
cleanup.push(() => observer.disconnect());
|
|
1625
1870
|
}
|
|
1626
|
-
function syncWindow(attached, win, zIndex, activeWorkspace) {
|
|
1871
|
+
function syncWindow(attached, win, zIndex, activeWorkspace, activeTab) {
|
|
1627
1872
|
const el = attached.element;
|
|
1628
1873
|
const firstSync = attached.lastState === null;
|
|
1629
1874
|
if (firstSync) el.style.transition = "none";
|
|
1630
|
-
if (attached.lastState !== win || attached.lastWorkspace !== activeWorkspace) {
|
|
1875
|
+
if (attached.lastState !== win || attached.lastWorkspace !== activeWorkspace || attached.lastTab !== activeTab) {
|
|
1631
1876
|
el.style.transform = `translate3d(${win.bounds.x}px, ${win.bounds.y}px, 0)`;
|
|
1632
1877
|
el.style.width = `${win.bounds.width}px`;
|
|
1633
1878
|
el.style.height = `${win.bounds.height}px`;
|
|
1634
1879
|
el.dataset.wmStage = win.stage;
|
|
1635
1880
|
el.dataset.wmLayer = win.layer;
|
|
1636
1881
|
el.dataset.wmWorkspace = String(win.workspace);
|
|
1637
|
-
|
|
1882
|
+
if (win.groupId === null) {
|
|
1883
|
+
delete el.dataset.wmGroup;
|
|
1884
|
+
delete el.dataset.wmTab;
|
|
1885
|
+
} else {
|
|
1886
|
+
el.dataset.wmGroup = win.groupId;
|
|
1887
|
+
el.dataset.wmTab = activeTab ? "active" : "inactive";
|
|
1888
|
+
}
|
|
1889
|
+
const hide = win.stage === "minimized" || win.workspace !== activeWorkspace || !activeTab;
|
|
1638
1890
|
if (hide && !el.hidden && el.contains(doc.activeElement)) {
|
|
1639
1891
|
element.focus({ preventScroll: true });
|
|
1640
1892
|
}
|
|
1893
|
+
if (!hide && el.hidden && wm.getState().focusedId === win.id) {
|
|
1894
|
+
queueMicrotask(() => {
|
|
1895
|
+
if (!el.hidden && !el.contains(doc.activeElement)) el.focus({ preventScroll: true });
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1641
1898
|
el.hidden = hide;
|
|
1642
1899
|
el.setAttribute("aria-label", win.title);
|
|
1643
1900
|
if (win.layer === "modal") el.setAttribute("aria-modal", "true");
|
|
@@ -1647,6 +1904,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1647
1904
|
}
|
|
1648
1905
|
attached.lastState = win;
|
|
1649
1906
|
attached.lastWorkspace = activeWorkspace;
|
|
1907
|
+
attached.lastTab = activeTab;
|
|
1650
1908
|
}
|
|
1651
1909
|
if (attached.lastZ !== zIndex) {
|
|
1652
1910
|
el.style.zIndex = String(zIndex + 1);
|
|
@@ -1664,8 +1922,9 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1664
1922
|
const attached = registry.get(id);
|
|
1665
1923
|
const win = state.windows[id];
|
|
1666
1924
|
if (!attached || !win) return;
|
|
1667
|
-
|
|
1668
|
-
|
|
1925
|
+
const activeTab = win.groupId === null || state.groups[win.groupId]?.activeId === win.id;
|
|
1926
|
+
if (orderChanged || attached.lastState !== win || attached.lastWorkspace !== state.workspace || attached.lastTab !== activeTab) {
|
|
1927
|
+
syncWindow(attached, win, index, state.workspace, activeTab);
|
|
1669
1928
|
}
|
|
1670
1929
|
});
|
|
1671
1930
|
if (state.focusedId !== lastFocused) {
|
|
@@ -1686,6 +1945,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1686
1945
|
wm.on("focus", ({ window: win }) => {
|
|
1687
1946
|
const attached = registry.get(win.id);
|
|
1688
1947
|
if (!attached) return;
|
|
1948
|
+
if (attached.element.hidden) syncAll();
|
|
1689
1949
|
if (!attached.element.contains(doc.activeElement)) {
|
|
1690
1950
|
attached.element.focus({ preventScroll: true });
|
|
1691
1951
|
}
|
|
@@ -1721,6 +1981,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1721
1981
|
return;
|
|
1722
1982
|
}
|
|
1723
1983
|
if (!event.ctrlKey && !event.metaKey) return;
|
|
1984
|
+
if (drag) return;
|
|
1724
1985
|
const target = event.target;
|
|
1725
1986
|
if (target?.closest(INTERACTIVE_SELECTOR)) return;
|
|
1726
1987
|
if (historyShortcuts && (event.key === "z" || event.key === "Z")) {
|
|
@@ -1766,6 +2027,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
1766
2027
|
lastState: null,
|
|
1767
2028
|
lastZ: -1,
|
|
1768
2029
|
lastWorkspace: -1,
|
|
2030
|
+
lastTab: true,
|
|
1769
2031
|
cleanup: []
|
|
1770
2032
|
};
|
|
1771
2033
|
windowElement.dataset.wmWindow = id;
|
|
@@ -2005,5 +2267,5 @@ exports.flipToTarget = flipToTarget;
|
|
|
2005
2267
|
exports.magnetize = magnetize;
|
|
2006
2268
|
exports.prefersReducedMotion = prefersReducedMotion;
|
|
2007
2269
|
exports.zoneBounds = zoneBounds;
|
|
2008
|
-
//# sourceMappingURL=chunk-
|
|
2009
|
-
//# sourceMappingURL=chunk-
|
|
2270
|
+
//# sourceMappingURL=chunk-RXAMUBUJ.cjs.map
|
|
2271
|
+
//# sourceMappingURL=chunk-RXAMUBUJ.cjs.map
|