@ai-matrx/summon 0.1.17 → 0.1.18
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/CHANGELOG.md +13 -1
- package/dist/chunk-server-C4KQZFIN.js +411 -0
- package/dist/chunk-server-C4KQZFIN.js.map +1 -0
- package/dist/chunk-server-H7NUWPEM.js +94 -0
- package/dist/chunk-server-H7NUWPEM.js.map +1 -0
- package/dist/chunk-server-WP7NOTZQ.js +208 -0
- package/dist/chunk-server-WP7NOTZQ.js.map +1 -0
- package/dist/dock.cjs +41 -112
- package/dist/dock.cjs.map +1 -1
- package/dist/dock.js +42 -113
- package/dist/dock.js.map +1 -1
- package/dist/handles.js +9 -272
- package/dist/handles.js.map +1 -1
- package/dist/index.js +350 -810
- package/dist/index.js.map +1 -1
- package/dist/lite.cjs +16 -76
- package/dist/lite.cjs.map +1 -1
- package/dist/lite.js +17 -77
- package/dist/lite.js.map +1 -1
- package/dist/open.js +74 -439
- package/dist/open.js.map +1 -1
- package/dist/window.cjs +167 -238
- package/dist/window.cjs.map +1 -1
- package/dist/window.d.cts +3 -1
- package/dist/window.d.ts +3 -1
- package/dist/window.js +55 -126
- package/dist/window.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,228 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
info: (message) => console.info(`[summon] ${message}`),
|
|
39
|
-
warn: (message) => console.warn(`[summon] ${message}`),
|
|
40
|
-
error: (message) => console.error(`[summon] ${message}`)
|
|
41
|
-
};
|
|
42
|
-
var consoleErrorSink = {
|
|
43
|
-
capture: (error, context) => console.error("[summon]", error, context)
|
|
44
|
-
};
|
|
45
|
-
var debugOff = { enabled: () => false };
|
|
46
|
-
var DEFAULT_PORTS = {
|
|
47
|
-
identity: anonymousIdentity,
|
|
48
|
-
router: locationRouter,
|
|
49
|
-
notify: consoleNotify,
|
|
50
|
-
errors: consoleErrorSink,
|
|
51
|
-
debug: debugOff,
|
|
52
|
-
persistence: null
|
|
53
|
-
};
|
|
54
|
-
function resolvePorts(overrides) {
|
|
55
|
-
return { ...DEFAULT_PORTS, ...overrides };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// src/core/registry.ts
|
|
59
|
-
import { globalSlot } from "@ai-matrx/kit/global-slot";
|
|
60
|
-
var state = () => globalSlot("ai-matrx.summon.registry", () => ({
|
|
61
|
-
byId: /* @__PURE__ */ new Map(),
|
|
62
|
-
byLinkKey: /* @__PURE__ */ new Map(),
|
|
63
|
-
listeners: /* @__PURE__ */ new Set()
|
|
64
|
-
}));
|
|
65
|
-
function registerOverlayMeta(definitions) {
|
|
66
|
-
const s = state();
|
|
67
|
-
for (const def of definitions) {
|
|
68
|
-
s.byId.set(def.id, def);
|
|
69
|
-
const keys = def.link ? [def.link.key, ...def.link.aliases ?? []] : [];
|
|
70
|
-
for (const key of keys) {
|
|
71
|
-
const holder = s.byLinkKey.get(key);
|
|
72
|
-
if (holder && holder.id !== def.id) {
|
|
73
|
-
throw new Error(`[summon] link key "${key}" is claimed by both "${holder.id}" and "${def.id}"`);
|
|
74
|
-
}
|
|
75
|
-
s.byLinkKey.set(key, def);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
for (const listener of s.listeners) listener();
|
|
79
|
-
}
|
|
80
|
-
function getOverlayMeta(overlayId) {
|
|
81
|
-
return state().byId.get(overlayId);
|
|
82
|
-
}
|
|
83
|
-
function getOverlayMetaByLinkKey(linkKey) {
|
|
84
|
-
return state().byLinkKey.get(linkKey);
|
|
85
|
-
}
|
|
86
|
-
function allOverlayMeta() {
|
|
87
|
-
return [...state().byId.values()];
|
|
88
|
-
}
|
|
89
|
-
function isRegisteredOverlay(overlayId) {
|
|
90
|
-
return state().byId.has(overlayId);
|
|
91
|
-
}
|
|
92
|
-
function subscribeToOverlayRegistry(listener) {
|
|
93
|
-
const s = state();
|
|
94
|
-
s.listeners.add(listener);
|
|
95
|
-
return () => s.listeners.delete(listener);
|
|
96
|
-
}
|
|
97
|
-
function resetOverlayRegistry() {
|
|
98
|
-
const s = state();
|
|
99
|
-
s.byId.clear();
|
|
100
|
-
s.byLinkKey.clear();
|
|
101
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_INSTANCE_ID,
|
|
3
|
+
DEFAULT_PORTS,
|
|
4
|
+
allOverlayMeta,
|
|
5
|
+
anonymousIdentity,
|
|
6
|
+
closeAllInstancesOfOverlay,
|
|
7
|
+
closeOverlay,
|
|
8
|
+
closeOverlaysBoundToPage,
|
|
9
|
+
consoleErrorSink,
|
|
10
|
+
consoleNotify,
|
|
11
|
+
debugOff,
|
|
12
|
+
defaultWindowIdFor,
|
|
13
|
+
dropPendingChannelsOf,
|
|
14
|
+
getOverlayMeta,
|
|
15
|
+
getOverlayMetaByLinkKey,
|
|
16
|
+
installSummonCore,
|
|
17
|
+
instanceKey,
|
|
18
|
+
isRegisteredOverlay,
|
|
19
|
+
listOpenInstanceKeys,
|
|
20
|
+
locationRouter,
|
|
21
|
+
openOverlay,
|
|
22
|
+
overlayIdsBoundToPage,
|
|
23
|
+
parseInstanceKey,
|
|
24
|
+
registerOverlayMeta,
|
|
25
|
+
resetOverlayRegistry,
|
|
26
|
+
resolvePorts,
|
|
27
|
+
selectIsOverlayOpen,
|
|
28
|
+
selectOpenInstances,
|
|
29
|
+
selectOverlay,
|
|
30
|
+
selectOverlayData,
|
|
31
|
+
subscribeToOverlayRegistry,
|
|
32
|
+
toggleOverlay
|
|
33
|
+
} from "./chunk-server-C4KQZFIN.js";
|
|
34
|
+
import {
|
|
35
|
+
callbackManager
|
|
36
|
+
} from "./chunk-server-WP7NOTZQ.js";
|
|
37
|
+
import "./chunk-server-H7NUWPEM.js";
|
|
102
38
|
|
|
103
39
|
// src/core/overlaysSlice.ts
|
|
104
40
|
import { createSlice } from "@reduxjs/toolkit";
|
|
105
|
-
|
|
106
|
-
// src/open/actions.ts
|
|
107
|
-
function creator(type, build) {
|
|
108
|
-
const create = (...args) => ({ type, payload: build(...args) });
|
|
109
|
-
return Object.assign(create, {
|
|
110
|
-
type,
|
|
111
|
-
toString: () => type,
|
|
112
|
-
match: (action) => typeof action === "object" && action !== null && action.type === type
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
function isPlainRecord(value) {
|
|
116
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
117
|
-
}
|
|
118
|
-
function stripFunctions(overlayId, data) {
|
|
119
|
-
if (!isPlainRecord(data)) return data;
|
|
120
|
-
const offenders = Object.keys(data).filter((key) => typeof data[key] === "function");
|
|
121
|
-
if (offenders.length === 0) return data;
|
|
122
|
-
console.error(
|
|
123
|
-
`[summon] BUG: function value(s) in openOverlay data for "${overlayId}" (keys: ${offenders.join(", ")}). Functions cannot travel through Redux \u2014 the handler would NEVER fire. Register a handle (@ai-matrx/summon/handles) and pass its id string instead. The offending key(s) were stripped from state.`
|
|
124
|
-
);
|
|
125
|
-
const cleaned = { ...data };
|
|
126
|
-
for (const key of offenders) delete cleaned[key];
|
|
127
|
-
return cleaned;
|
|
128
|
-
}
|
|
129
|
-
function rawOpen(payload) {
|
|
130
|
-
const raw = { overlayId: payload.overlayId };
|
|
131
|
-
if (payload.instanceId !== void 0) raw.instanceId = payload.instanceId;
|
|
132
|
-
if (payload.data !== void 0) raw.data = stripFunctions(payload.overlayId, payload.data);
|
|
133
|
-
const defaults = getOverlayMeta(payload.overlayId)?.defaults;
|
|
134
|
-
if (isPlainRecord(defaults)) raw.defaults = stripFunctions(payload.overlayId, defaults);
|
|
135
|
-
return raw;
|
|
136
|
-
}
|
|
137
|
-
var O = "overlays/";
|
|
138
|
-
var openOverlay = creator(O + "openOverlay", (payload) => rawOpen(payload));
|
|
139
|
-
var closeOverlay = creator(
|
|
140
|
-
O + "closeOverlay",
|
|
141
|
-
(payload) => payload.instanceId === void 0 ? { overlayId: payload.overlayId } : { overlayId: payload.overlayId, instanceId: payload.instanceId }
|
|
142
|
-
);
|
|
143
|
-
var toggleOverlay = creator(O + "toggleOverlay", (payload) => rawOpen(payload));
|
|
144
|
-
var closeAllInstancesOfOverlay = creator(O + "closeAllInstancesOfOverlay", (payload) => ({
|
|
145
|
-
overlayId: payload.overlayId
|
|
146
|
-
}));
|
|
147
|
-
function overlayIdsBoundToPage() {
|
|
148
|
-
return allOverlayMeta().filter((meta) => meta.closesOnNavigation === true).map((meta) => meta.id);
|
|
149
|
-
}
|
|
150
|
-
var closeOverlaysBoundToPage = creator(
|
|
151
|
-
O + "closeOverlaysBoundToPage",
|
|
152
|
-
(payload) => ({
|
|
153
|
-
overlayIds: [...payload?.overlayIds ?? overlayIdsBoundToPage()]
|
|
154
|
-
})
|
|
155
|
-
);
|
|
156
|
-
var closeAllOverlays = creator(O + "closeAllOverlays", () => void 0);
|
|
157
|
-
var pruneStaleInstances = creator(O + "pruneStaleInstances", (payload) => payload);
|
|
158
|
-
var W = "windowManager/";
|
|
159
|
-
var pass = () => (payload) => payload;
|
|
160
|
-
var focusWindow = creator(W + "focusWindow", pass());
|
|
161
|
-
var restoreWindow = creator(W + "restoreWindow", pass());
|
|
162
|
-
var toggleWindowsHidden = creator(W + "toggleWindowsHidden", () => void 0);
|
|
163
|
-
var restoreAll = creator(W + "restoreAll", () => void 0);
|
|
164
|
-
var minimizeAll = creator(W + "minimizeAll", pass());
|
|
165
|
-
var arrangeActiveWindows = creator(W + "arrangeActiveWindows", pass());
|
|
166
|
-
var revealWindow = creator(W + "revealWindow", pass());
|
|
167
|
-
var updateWindowRect = creator(
|
|
168
|
-
W + "updateWindowRect",
|
|
169
|
-
pass()
|
|
170
|
-
);
|
|
171
|
-
var setOverlayStateValue = creator("overlayState/setOverlayStateValue", pass());
|
|
172
|
-
var registerSyncEntry = creator("urlSync/registerSyncEntry", pass());
|
|
173
|
-
var unregisterSyncEntry = creator("urlSync/unregisterSyncEntry", pass());
|
|
174
|
-
|
|
175
|
-
// src/open/selectors.ts
|
|
176
|
-
import { globalSlot as globalSlot2 } from "@ai-matrx/kit/global-slot";
|
|
177
|
-
var overlaysOf = (state2) => state2.overlays;
|
|
178
|
-
var CLOSED = Object.freeze({ isOpen: false, data: null });
|
|
179
|
-
var EMPTY = Object.freeze([]);
|
|
180
|
-
var selectOverlay = (state2, overlayId, instanceId = DEFAULT_INSTANCE_ID) => overlaysOf(state2)?.overlays[overlayId]?.[instanceId] ?? CLOSED;
|
|
181
|
-
var selectIsOverlayOpen = (state2, overlayId, instanceId = DEFAULT_INSTANCE_ID) => selectOverlay(state2, overlayId, instanceId).isOpen;
|
|
182
|
-
var selectOverlayData = (state2, overlayId, instanceId = DEFAULT_INSTANCE_ID) => selectOverlay(state2, overlayId, instanceId).data;
|
|
183
|
-
var openCache = () => globalSlot2("ai-matrx.summon.openInstances", () => /* @__PURE__ */ new Map());
|
|
184
|
-
var selectOpenInstances = (state2, overlayId) => {
|
|
185
|
-
const bucket = overlaysOf(state2)?.overlays[overlayId];
|
|
186
|
-
const cache = openCache();
|
|
187
|
-
const hit = cache.get(overlayId);
|
|
188
|
-
if (hit && hit.bucket === bucket) return hit.result;
|
|
189
|
-
let result = EMPTY;
|
|
190
|
-
if (bucket) {
|
|
191
|
-
const open = [];
|
|
192
|
-
for (const [instanceId, inst] of Object.entries(bucket)) if (inst.isOpen) open.push({ instanceId, data: inst.data });
|
|
193
|
-
if (open.length > 0) result = open;
|
|
194
|
-
}
|
|
195
|
-
cache.set(overlayId, { bucket, result });
|
|
196
|
-
return result;
|
|
197
|
-
};
|
|
198
|
-
function listOpenInstanceKeys(state2) {
|
|
199
|
-
const keys = [];
|
|
200
|
-
for (const [overlayId, bucket] of Object.entries(overlaysOf(state2)?.overlays ?? {})) {
|
|
201
|
-
for (const [instanceId, inst] of Object.entries(bucket)) if (inst.isOpen) keys.push(`${overlayId}:${instanceId}`);
|
|
202
|
-
}
|
|
203
|
-
return keys;
|
|
204
|
-
}
|
|
205
|
-
var EMPTY_WINDOWS = Object.freeze([]);
|
|
206
|
-
|
|
207
|
-
// src/core/overlaysSlice.ts
|
|
208
41
|
var initialState = { overlays: {} };
|
|
209
|
-
function
|
|
42
|
+
function isPlainRecord(value) {
|
|
210
43
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
211
44
|
}
|
|
212
45
|
function withDefaults(data, defaults) {
|
|
213
46
|
if (!defaults) return data ?? null;
|
|
214
47
|
if (data === void 0 || data === null) return { ...defaults };
|
|
215
|
-
if (
|
|
48
|
+
if (isPlainRecord(data)) return { ...defaults, ...data };
|
|
216
49
|
return data;
|
|
217
50
|
}
|
|
218
|
-
function closeInstance(
|
|
219
|
-
const bucket =
|
|
51
|
+
function closeInstance(state, overlayId, instanceId) {
|
|
52
|
+
const bucket = state.overlays[overlayId];
|
|
220
53
|
if (!bucket) return;
|
|
221
54
|
const instance = bucket[instanceId];
|
|
222
55
|
if (!instance) return;
|
|
223
56
|
if (instanceId !== DEFAULT_INSTANCE_ID) {
|
|
224
57
|
delete bucket[instanceId];
|
|
225
|
-
if (Object.keys(bucket).length === 0) delete
|
|
58
|
+
if (Object.keys(bucket).length === 0) delete state.overlays[overlayId];
|
|
226
59
|
return;
|
|
227
60
|
}
|
|
228
61
|
instance.isOpen = false;
|
|
@@ -232,17 +65,17 @@ var overlaysSlice = createSlice({
|
|
|
232
65
|
name: "overlays",
|
|
233
66
|
initialState,
|
|
234
67
|
reducers: {
|
|
235
|
-
openOverlay: (
|
|
68
|
+
openOverlay: (state, action) => {
|
|
236
69
|
const { overlayId, instanceId = DEFAULT_INSTANCE_ID, data, defaults } = action.payload;
|
|
237
|
-
const bucket =
|
|
70
|
+
const bucket = state.overlays[overlayId] ??= {};
|
|
238
71
|
bucket[instanceId] = { isOpen: true, data: withDefaults(data, defaults), lastUsedAt: Date.now() };
|
|
239
72
|
},
|
|
240
|
-
closeOverlay: (
|
|
73
|
+
closeOverlay: (state, action) => {
|
|
241
74
|
const { overlayId, instanceId = DEFAULT_INSTANCE_ID } = action.payload;
|
|
242
|
-
closeInstance(
|
|
75
|
+
closeInstance(state, overlayId, instanceId);
|
|
243
76
|
},
|
|
244
|
-
closeAllOverlays: (
|
|
245
|
-
for (const [overlayId, bucket] of Object.entries(
|
|
77
|
+
closeAllOverlays: (state) => {
|
|
78
|
+
for (const [overlayId, bucket] of Object.entries(state.overlays)) {
|
|
246
79
|
for (const [instanceId, instance] of Object.entries(bucket)) {
|
|
247
80
|
if (instanceId === DEFAULT_INSTANCE_ID) {
|
|
248
81
|
instance.isOpen = false;
|
|
@@ -251,17 +84,17 @@ var overlaysSlice = createSlice({
|
|
|
251
84
|
delete bucket[instanceId];
|
|
252
85
|
}
|
|
253
86
|
}
|
|
254
|
-
if (Object.keys(bucket).length === 0) delete
|
|
87
|
+
if (Object.keys(bucket).length === 0) delete state.overlays[overlayId];
|
|
255
88
|
}
|
|
256
89
|
},
|
|
257
|
-
toggleOverlay: (
|
|
90
|
+
toggleOverlay: (state, action) => {
|
|
258
91
|
const { overlayId, instanceId = DEFAULT_INSTANCE_ID, data, defaults } = action.payload;
|
|
259
|
-
const bucket =
|
|
92
|
+
const bucket = state.overlays[overlayId] ??= {};
|
|
260
93
|
const existing = bucket[instanceId];
|
|
261
94
|
if (!existing) {
|
|
262
95
|
bucket[instanceId] = { isOpen: true, data: withDefaults(data, defaults), lastUsedAt: Date.now() };
|
|
263
96
|
} else if (existing.isOpen) {
|
|
264
|
-
closeInstance(
|
|
97
|
+
closeInstance(state, overlayId, instanceId);
|
|
265
98
|
} else {
|
|
266
99
|
existing.isOpen = true;
|
|
267
100
|
existing.data = data === void 0 || data === null ? existing.data : withDefaults(data, defaults);
|
|
@@ -269,17 +102,17 @@ var overlaysSlice = createSlice({
|
|
|
269
102
|
}
|
|
270
103
|
},
|
|
271
104
|
/** Removes every instance of an overlay id (e.g. an editor that spawned many tabs). */
|
|
272
|
-
closeAllInstancesOfOverlay: (
|
|
273
|
-
delete
|
|
105
|
+
closeAllInstancesOfOverlay: (state, action) => {
|
|
106
|
+
delete state.overlays[action.payload.overlayId];
|
|
274
107
|
},
|
|
275
108
|
/**
|
|
276
109
|
* Route change: close every open instance of the listed overlays — each shows a piece of the
|
|
277
110
|
* page that opened it, so after navigating away it would float over a page it does not
|
|
278
111
|
* belong to. Every other overlay is a workbench tool and stays open.
|
|
279
112
|
*/
|
|
280
|
-
closeOverlaysBoundToPage: (
|
|
113
|
+
closeOverlaysBoundToPage: (state, action) => {
|
|
281
114
|
for (const overlayId of action.payload.overlayIds) {
|
|
282
|
-
const bucket =
|
|
115
|
+
const bucket = state.overlays[overlayId];
|
|
283
116
|
if (!bucket) continue;
|
|
284
117
|
for (const [instanceId, instance] of Object.entries(bucket)) {
|
|
285
118
|
if (!instance.isOpen) continue;
|
|
@@ -290,29 +123,29 @@ var overlaysSlice = createSlice({
|
|
|
290
123
|
delete bucket[instanceId];
|
|
291
124
|
}
|
|
292
125
|
}
|
|
293
|
-
if (Object.keys(bucket).length === 0) delete
|
|
126
|
+
if (Object.keys(bucket).length === 0) delete state.overlays[overlayId];
|
|
294
127
|
}
|
|
295
128
|
},
|
|
296
129
|
/**
|
|
297
130
|
* GC pass — removes closed instances last used more than `olderThanMs` ago. Singleton slots
|
|
298
131
|
* are kept regardless so selectors returning stable references don't thrash.
|
|
299
132
|
*/
|
|
300
|
-
pruneStaleInstances: (
|
|
133
|
+
pruneStaleInstances: (state, action) => {
|
|
301
134
|
const cutoff = Date.now() - action.payload.olderThanMs;
|
|
302
|
-
for (const [overlayId, bucket] of Object.entries(
|
|
135
|
+
for (const [overlayId, bucket] of Object.entries(state.overlays)) {
|
|
303
136
|
for (const [instanceId, instance] of Object.entries(bucket)) {
|
|
304
137
|
if (instanceId === DEFAULT_INSTANCE_ID) continue;
|
|
305
138
|
if (instance.isOpen) continue;
|
|
306
139
|
if (!instance.lastUsedAt || instance.lastUsedAt < cutoff) delete bucket[instanceId];
|
|
307
140
|
}
|
|
308
|
-
if (Object.keys(bucket).length === 0) delete
|
|
141
|
+
if (Object.keys(bucket).length === 0) delete state.overlays[overlayId];
|
|
309
142
|
}
|
|
310
143
|
}
|
|
311
144
|
}
|
|
312
145
|
});
|
|
313
146
|
var overlaysReducer = overlaysSlice.reducer;
|
|
314
147
|
var overlaysRawActions = overlaysSlice.actions;
|
|
315
|
-
var { closeAllOverlays
|
|
148
|
+
var { closeAllOverlays, pruneStaleInstances } = overlaysSlice.actions;
|
|
316
149
|
|
|
317
150
|
// src/core/windowManagerSlice.ts
|
|
318
151
|
import {
|
|
@@ -618,11 +451,11 @@ function trayChipsPerRow(viewportWidth) {
|
|
|
618
451
|
Math.floor((usable + TRAY_GAP_X) / (chipWidth + TRAY_GAP_X))
|
|
619
452
|
);
|
|
620
453
|
}
|
|
621
|
-
function traySlotRect(
|
|
454
|
+
function traySlotRect(slot, viewportWidth, viewportHeight, totalSlots = slot + 1) {
|
|
622
455
|
const chipWidth = computeTrayChipWidth(viewportWidth);
|
|
623
456
|
const chipHeight = computeTrayChipHeight(viewportWidth);
|
|
624
457
|
const perRow = trayChipsPerRow(viewportWidth);
|
|
625
|
-
const safeSlot = Math.max(0, Math.floor(
|
|
458
|
+
const safeSlot = Math.max(0, Math.floor(slot));
|
|
626
459
|
const usableHeight = Math.max(1, viewportHeight - TRAY_MARGIN_B - 8);
|
|
627
460
|
const fullRows = Math.max(
|
|
628
461
|
1,
|
|
@@ -684,71 +517,71 @@ var initialState2 = {
|
|
|
684
517
|
popoutCandidateId: null,
|
|
685
518
|
transientZ: {}
|
|
686
519
|
};
|
|
687
|
-
function recomputeAllTrayRects(
|
|
688
|
-
const viewport =
|
|
520
|
+
function recomputeAllTrayRects(state) {
|
|
521
|
+
const viewport = state.trayViewport;
|
|
689
522
|
if (!viewport) return;
|
|
690
|
-
Object.values(
|
|
523
|
+
Object.values(state.windows).forEach((entry) => {
|
|
691
524
|
if (entry.traySlot === null) return;
|
|
692
525
|
entry.windowed = traySlotRect(
|
|
693
526
|
entry.traySlot,
|
|
694
527
|
viewport.width,
|
|
695
528
|
viewport.height,
|
|
696
|
-
|
|
529
|
+
state.trayCount
|
|
697
530
|
);
|
|
698
531
|
});
|
|
699
|
-
Object.values(
|
|
532
|
+
Object.values(state.pendingRestores).forEach((session) => {
|
|
700
533
|
if (session.traySlot === null) return;
|
|
701
534
|
session.renderRect = traySlotRect(
|
|
702
535
|
session.traySlot,
|
|
703
536
|
viewport.width,
|
|
704
537
|
viewport.height,
|
|
705
|
-
|
|
538
|
+
state.trayCount
|
|
706
539
|
);
|
|
707
540
|
});
|
|
708
541
|
}
|
|
709
|
-
function hasMatchingLiveTrayReservation(
|
|
542
|
+
function hasMatchingLiveTrayReservation(state, overlayId, instanceId, traySlot) {
|
|
710
543
|
if (traySlot === null) return false;
|
|
711
|
-
return Object.values(
|
|
544
|
+
return Object.values(state.windows).some(
|
|
712
545
|
(entry) => entry.persistence?.overlayId === overlayId && entry.persistence.instanceId === instanceId && entry.traySlot === traySlot
|
|
713
546
|
);
|
|
714
547
|
}
|
|
715
|
-
function compactReservedTraySlot(
|
|
548
|
+
function compactReservedTraySlot(state, freedSlot, freedRect) {
|
|
716
549
|
const rectBySlot = /* @__PURE__ */ new Map();
|
|
717
550
|
rectBySlot.set(freedSlot, freedRect);
|
|
718
|
-
Object.values(
|
|
551
|
+
Object.values(state.windows).forEach((entry) => {
|
|
719
552
|
if (entry.traySlot !== null) {
|
|
720
553
|
rectBySlot.set(entry.traySlot, { ...entry.windowed });
|
|
721
554
|
}
|
|
722
555
|
});
|
|
723
|
-
Object.values(
|
|
556
|
+
Object.values(state.pendingRestores).forEach((session) => {
|
|
724
557
|
if (session.traySlot !== null) {
|
|
725
558
|
rectBySlot.set(session.traySlot, { ...session.renderRect });
|
|
726
559
|
}
|
|
727
560
|
});
|
|
728
|
-
|
|
729
|
-
if (
|
|
730
|
-
Object.values(
|
|
561
|
+
state.trayCount = Math.max(0, state.trayCount - 1);
|
|
562
|
+
if (state.trayCount === 0) state.trayViewport = null;
|
|
563
|
+
Object.values(state.windows).forEach((entry) => {
|
|
731
564
|
if (entry.traySlot === null || entry.traySlot <= freedSlot) return;
|
|
732
565
|
const nextSlot = entry.traySlot - 1;
|
|
733
566
|
entry.traySlot = nextSlot;
|
|
734
567
|
const nextRect = rectBySlot.get(nextSlot);
|
|
735
568
|
if (nextRect) entry.windowed = nextRect;
|
|
736
569
|
});
|
|
737
|
-
Object.values(
|
|
570
|
+
Object.values(state.pendingRestores).forEach((session) => {
|
|
738
571
|
if (session.traySlot === null || session.traySlot <= freedSlot) return;
|
|
739
572
|
const nextSlot = session.traySlot - 1;
|
|
740
573
|
session.traySlot = nextSlot;
|
|
741
574
|
const nextRect = rectBySlot.get(nextSlot);
|
|
742
575
|
if (nextRect) session.renderRect = nextRect;
|
|
743
576
|
});
|
|
744
|
-
recomputeAllTrayRects(
|
|
577
|
+
recomputeAllTrayRects(state);
|
|
745
578
|
}
|
|
746
|
-
function releaseTraySlot(
|
|
579
|
+
function releaseTraySlot(state, win) {
|
|
747
580
|
const freedSlot = win.traySlot;
|
|
748
581
|
if (freedSlot === null) return;
|
|
749
582
|
const freedRect = { ...win.windowed };
|
|
750
583
|
win.traySlot = null;
|
|
751
|
-
compactReservedTraySlot(
|
|
584
|
+
compactReservedTraySlot(state, freedSlot, freedRect);
|
|
752
585
|
}
|
|
753
586
|
var windowManagerSlice = createSlice2({
|
|
754
587
|
name: "windowManager",
|
|
@@ -759,73 +592,73 @@ var windowManagerSlice = createSlice2({
|
|
|
759
592
|
* that is already there. Same counter as `focusWindow`, so heavy and lite
|
|
760
593
|
* windows interleave correctly.
|
|
761
594
|
*/
|
|
762
|
-
raiseTransientWindow(
|
|
763
|
-
|
|
595
|
+
raiseTransientWindow(state, action) {
|
|
596
|
+
state.transientZ[action.payload] = state.nextZIndex++;
|
|
764
597
|
},
|
|
765
598
|
/** Drop a transient window's z registration when it unmounts. */
|
|
766
|
-
releaseTransientWindow(
|
|
767
|
-
delete
|
|
599
|
+
releaseTransientWindow(state, action) {
|
|
600
|
+
delete state.transientZ[action.payload];
|
|
768
601
|
},
|
|
769
602
|
/** Register a new window. Idempotent — ignored if id already exists. */
|
|
770
|
-
registerWindow(
|
|
603
|
+
registerWindow(state, action) {
|
|
771
604
|
const { id, title, initial, initialState: initialState5, persistence, viewport } = action.payload;
|
|
772
|
-
if (
|
|
605
|
+
if (state.windows[id]) return;
|
|
773
606
|
const safeInitial = viewport ? clampRectToViewport(initial, viewport) : initial;
|
|
774
|
-
const
|
|
775
|
-
const pendingRenderRect =
|
|
776
|
-
|
|
607
|
+
const pending = persistence ? state.pendingRestores[windowSessionKey(persistence.overlayId, persistence.instanceId)] : void 0;
|
|
608
|
+
const pendingRenderRect = pending ? pending.state === "minimized" && pending.traySlot !== null && viewport ? traySlotRect(
|
|
609
|
+
pending.traySlot,
|
|
777
610
|
viewport.width,
|
|
778
611
|
viewport.height,
|
|
779
|
-
|
|
780
|
-
) : viewport ? clampRectToViewport(
|
|
781
|
-
const startsMinimized = !
|
|
782
|
-
const initialTraySlot = startsMinimized ?
|
|
783
|
-
|
|
612
|
+
state.trayCount
|
|
613
|
+
) : viewport ? clampRectToViewport(pending.windowedRect, viewport) : pending.renderRect : void 0;
|
|
614
|
+
const startsMinimized = !pending && initialState5 === "minimized" && viewport !== void 0;
|
|
615
|
+
const initialTraySlot = startsMinimized ? state.trayCount : null;
|
|
616
|
+
state.windows[id] = {
|
|
784
617
|
id,
|
|
785
|
-
title: title ??
|
|
786
|
-
state:
|
|
618
|
+
title: title ?? pending?.title ?? id,
|
|
619
|
+
state: pending?.state ?? (startsMinimized ? "minimized" : "windowed"),
|
|
787
620
|
windowed: pendingRenderRect ?? safeInitial,
|
|
788
|
-
preMinimizedRect:
|
|
789
|
-
zIndex:
|
|
790
|
-
traySlot:
|
|
621
|
+
preMinimizedRect: pending?.state === "minimized" ? pending.windowedRect : startsMinimized ? safeInitial : null,
|
|
622
|
+
zIndex: pending?.zIndex ?? state.nextZIndex++,
|
|
623
|
+
traySlot: pending?.state === "minimized" ? pending.traySlot : initialTraySlot,
|
|
791
624
|
popoutMode: null,
|
|
792
625
|
prePopoutRect: null,
|
|
793
626
|
...persistence ? {
|
|
794
627
|
persistence: {
|
|
795
628
|
...persistence,
|
|
796
|
-
data: { ...
|
|
797
|
-
sidebarOpen:
|
|
798
|
-
sidebarSize:
|
|
629
|
+
data: { ...pending?.data ?? {}, ...persistence.data },
|
|
630
|
+
sidebarOpen: pending?.sidebarOpen ?? persistence.sidebarOpen,
|
|
631
|
+
sidebarSize: pending?.sidebarSize ?? persistence.sidebarSize,
|
|
799
632
|
closing: false
|
|
800
633
|
}
|
|
801
634
|
} : {}
|
|
802
635
|
};
|
|
803
|
-
if (
|
|
804
|
-
|
|
636
|
+
if (pending?.state === "minimized" && pending.traySlot !== null) {
|
|
637
|
+
state.trayCount = Math.max(state.trayCount, pending.traySlot + 1);
|
|
805
638
|
} else if (startsMinimized && viewport) {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
recomputeAllTrayRects(
|
|
639
|
+
state.trayCount += 1;
|
|
640
|
+
state.trayViewport = viewport;
|
|
641
|
+
recomputeAllTrayRects(state);
|
|
809
642
|
}
|
|
810
|
-
if (
|
|
811
|
-
|
|
643
|
+
if (pending && pending.zIndex >= state.nextZIndex) {
|
|
644
|
+
state.nextZIndex = pending.zIndex + 1;
|
|
812
645
|
}
|
|
813
|
-
if (
|
|
646
|
+
if (state.windowsHidden) state.windowsHidden = false;
|
|
814
647
|
},
|
|
815
648
|
/** Stage validated local sessions without creating phantom live windows. */
|
|
816
|
-
hydrateWindowSessions(
|
|
817
|
-
const liveEntries = Object.values(
|
|
649
|
+
hydrateWindowSessions(state, action) {
|
|
650
|
+
const liveEntries = Object.values(state.windows).sort(
|
|
818
651
|
(a, b) => a.zIndex - b.zIndex || a.id.localeCompare(b.id)
|
|
819
652
|
);
|
|
820
653
|
const accepted = [];
|
|
821
654
|
action.payload.sessions.forEach((session) => {
|
|
822
|
-
const alreadyLive = Object.values(
|
|
655
|
+
const alreadyLive = Object.values(state.windows).some(
|
|
823
656
|
(entry) => entry.persistence?.overlayId === session.overlayId && entry.persistence.instanceId === session.instanceId && !entry.persistence.closing
|
|
824
657
|
);
|
|
825
658
|
if (alreadyLive) return;
|
|
826
659
|
accepted.push(session);
|
|
827
660
|
});
|
|
828
|
-
const trayBase =
|
|
661
|
+
const trayBase = state.trayCount;
|
|
829
662
|
const acceptedTraySlots = new Map(
|
|
830
663
|
accepted.filter(
|
|
831
664
|
(session) => session.state === "minimized" && session.traySlot !== null
|
|
@@ -840,7 +673,7 @@ var windowManagerSlice = createSlice2({
|
|
|
840
673
|
).forEach((session, index) => {
|
|
841
674
|
const key = windowSessionKey(session.overlayId, session.instanceId);
|
|
842
675
|
const traySlot = session.state === "minimized" ? acceptedTraySlots.get(session.sessionKey) ?? null : null;
|
|
843
|
-
|
|
676
|
+
state.pendingRestores[key] = {
|
|
844
677
|
...session,
|
|
845
678
|
sessionKey: key,
|
|
846
679
|
traySlot,
|
|
@@ -855,35 +688,35 @@ var windowManagerSlice = createSlice2({
|
|
|
855
688
|
})
|
|
856
689
|
};
|
|
857
690
|
});
|
|
858
|
-
|
|
859
|
-
|
|
691
|
+
state.trayCount = trayBase + acceptedTraySlots.size;
|
|
692
|
+
state.trayViewport = {
|
|
860
693
|
width: action.payload.viewportWidth,
|
|
861
694
|
height: action.payload.viewportHeight
|
|
862
695
|
};
|
|
863
|
-
recomputeAllTrayRects(
|
|
696
|
+
recomputeAllTrayRects(state);
|
|
864
697
|
liveEntries.forEach((entry, index) => {
|
|
865
698
|
entry.zIndex = BASE_Z + accepted.length + index;
|
|
866
699
|
});
|
|
867
|
-
|
|
700
|
+
state.nextZIndex = BASE_Z + accepted.length + liveEntries.length;
|
|
868
701
|
},
|
|
869
702
|
/** StrictMode-safe: the first mount cleanup may run before the real mount settles. */
|
|
870
|
-
confirmWindowRestored(
|
|
871
|
-
delete
|
|
703
|
+
confirmWindowRestored(state, action) {
|
|
704
|
+
delete state.pendingRestores[action.payload];
|
|
872
705
|
},
|
|
873
|
-
discardPendingWindowSession(
|
|
874
|
-
const
|
|
875
|
-
if (
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
706
|
+
discardPendingWindowSession(state, action) {
|
|
707
|
+
const pending = state.pendingRestores[action.payload];
|
|
708
|
+
if (pending?.traySlot !== null && pending?.traySlot !== void 0 && !hasMatchingLiveTrayReservation(
|
|
709
|
+
state,
|
|
710
|
+
pending.overlayId,
|
|
711
|
+
pending.instanceId,
|
|
712
|
+
pending.traySlot
|
|
880
713
|
)) {
|
|
881
|
-
compactReservedTraySlot(
|
|
714
|
+
compactReservedTraySlot(state, pending.traySlot, pending.renderRect);
|
|
882
715
|
}
|
|
883
|
-
delete
|
|
716
|
+
delete state.pendingRestores[action.payload];
|
|
884
717
|
},
|
|
885
|
-
updateWindowPersistence(
|
|
886
|
-
const entry =
|
|
718
|
+
updateWindowPersistence(state, action) {
|
|
719
|
+
const entry = state.windows[action.payload.id];
|
|
887
720
|
if (!entry?.persistence || entry.persistence.closing) return;
|
|
888
721
|
if (action.payload.data !== void 0 && JSON.stringify(entry.persistence.data) !== JSON.stringify(action.payload.data)) {
|
|
889
722
|
entry.persistence.data = action.payload.data;
|
|
@@ -896,32 +729,32 @@ var windowManagerSlice = createSlice2({
|
|
|
896
729
|
}
|
|
897
730
|
},
|
|
898
731
|
/** Synchronous tombstone: close can never be undone by an unmount snapshot. */
|
|
899
|
-
markWindowClosing(
|
|
732
|
+
markWindowClosing(state, action) {
|
|
900
733
|
const key = windowSessionKey(
|
|
901
734
|
action.payload.overlayId,
|
|
902
735
|
action.payload.instanceId
|
|
903
736
|
);
|
|
904
|
-
const
|
|
905
|
-
const hasMatchingLiveReservation =
|
|
906
|
-
|
|
737
|
+
const pending = state.pendingRestores[key];
|
|
738
|
+
const hasMatchingLiveReservation = pending ? hasMatchingLiveTrayReservation(
|
|
739
|
+
state,
|
|
907
740
|
action.payload.overlayId,
|
|
908
741
|
action.payload.instanceId,
|
|
909
|
-
|
|
742
|
+
pending.traySlot
|
|
910
743
|
) : false;
|
|
911
|
-
if (!hasMatchingLiveReservation &&
|
|
912
|
-
compactReservedTraySlot(
|
|
744
|
+
if (!hasMatchingLiveReservation && pending?.traySlot !== null && pending?.traySlot !== void 0) {
|
|
745
|
+
compactReservedTraySlot(state, pending.traySlot, pending.renderRect);
|
|
913
746
|
}
|
|
914
|
-
delete
|
|
915
|
-
Object.values(
|
|
747
|
+
delete state.pendingRestores[key];
|
|
748
|
+
Object.values(state.windows).forEach((entry) => {
|
|
916
749
|
if (entry.persistence?.overlayId === action.payload.overlayId && entry.persistence.instanceId === action.payload.instanceId) {
|
|
917
750
|
entry.persistence.closing = true;
|
|
918
751
|
}
|
|
919
752
|
});
|
|
920
753
|
},
|
|
921
|
-
clearWindowPersistenceState(
|
|
922
|
-
Object.values(
|
|
754
|
+
clearWindowPersistenceState(state) {
|
|
755
|
+
Object.values(state.pendingRestores).filter(
|
|
923
756
|
(session) => session.traySlot !== null && session.traySlot !== void 0 && !hasMatchingLiveTrayReservation(
|
|
924
|
-
|
|
757
|
+
state,
|
|
925
758
|
session.overlayId,
|
|
926
759
|
session.instanceId,
|
|
927
760
|
session.traySlot
|
|
@@ -929,63 +762,63 @@ var windowManagerSlice = createSlice2({
|
|
|
929
762
|
).sort((a, b) => (b.traySlot ?? -1) - (a.traySlot ?? -1)).forEach((session) => {
|
|
930
763
|
const traySlot = session.traySlot;
|
|
931
764
|
if (traySlot === null) return;
|
|
932
|
-
compactReservedTraySlot(
|
|
765
|
+
compactReservedTraySlot(state, traySlot, session.renderRect);
|
|
933
766
|
});
|
|
934
|
-
|
|
935
|
-
Object.values(
|
|
767
|
+
state.pendingRestores = {};
|
|
768
|
+
Object.values(state.windows).forEach((entry) => {
|
|
936
769
|
if (entry.persistence) entry.persistence.closing = true;
|
|
937
770
|
});
|
|
938
771
|
},
|
|
939
772
|
/** Update just the title (e.g. when prop changes). */
|
|
940
|
-
updateWindowTitle(
|
|
941
|
-
const win =
|
|
773
|
+
updateWindowTitle(state, action) {
|
|
774
|
+
const win = state.windows[action.payload.id];
|
|
942
775
|
if (win) win.title = action.payload.title;
|
|
943
776
|
},
|
|
944
777
|
/** Remove a window from tracking entirely. */
|
|
945
|
-
unregisterWindow(
|
|
946
|
-
const win =
|
|
778
|
+
unregisterWindow(state, action) {
|
|
779
|
+
const win = state.windows[action.payload];
|
|
947
780
|
if (!win) return;
|
|
948
|
-
const
|
|
781
|
+
const pending = win.persistence ? state.pendingRestores[windowSessionKey(
|
|
949
782
|
win.persistence.overlayId,
|
|
950
783
|
win.persistence.instanceId
|
|
951
784
|
)] : void 0;
|
|
952
785
|
const pendingOwnsLiveReservation = Boolean(
|
|
953
|
-
win.persistence &&
|
|
954
|
-
|
|
786
|
+
win.persistence && pending && hasMatchingLiveTrayReservation(
|
|
787
|
+
state,
|
|
955
788
|
win.persistence.overlayId,
|
|
956
789
|
win.persistence.instanceId,
|
|
957
|
-
|
|
790
|
+
pending.traySlot
|
|
958
791
|
)
|
|
959
792
|
);
|
|
960
|
-
if (!pendingOwnsLiveReservation) releaseTraySlot(
|
|
961
|
-
if (
|
|
962
|
-
|
|
793
|
+
if (!pendingOwnsLiveReservation) releaseTraySlot(state, win);
|
|
794
|
+
if (state.activePipWindowId === action.payload) {
|
|
795
|
+
state.activePipWindowId = null;
|
|
963
796
|
}
|
|
964
|
-
if (
|
|
965
|
-
|
|
797
|
+
if (state.popoutCandidateId === action.payload) {
|
|
798
|
+
state.popoutCandidateId = null;
|
|
966
799
|
}
|
|
967
|
-
delete
|
|
968
|
-
if (Object.keys(
|
|
969
|
-
|
|
800
|
+
delete state.windows[action.payload];
|
|
801
|
+
if (Object.keys(state.windows).length === 0) {
|
|
802
|
+
state.windowsHidden = false;
|
|
970
803
|
}
|
|
971
804
|
},
|
|
972
805
|
/** Bring a window to the top of the z stack. */
|
|
973
|
-
focusWindow(
|
|
974
|
-
const win =
|
|
806
|
+
focusWindow(state, action) {
|
|
807
|
+
const win = state.windows[action.payload];
|
|
975
808
|
if (!win) return;
|
|
976
|
-
win.zIndex =
|
|
809
|
+
win.zIndex = state.nextZIndex++;
|
|
977
810
|
},
|
|
978
811
|
/** Switch to windowed (restore) state. */
|
|
979
|
-
restoreWindow(
|
|
980
|
-
const win =
|
|
812
|
+
restoreWindow(state, action) {
|
|
813
|
+
const win = state.windows[action.payload];
|
|
981
814
|
if (!win) return;
|
|
982
|
-
releaseTraySlot(
|
|
815
|
+
releaseTraySlot(state, win);
|
|
983
816
|
if (win.preMinimizedRect) {
|
|
984
817
|
win.windowed = win.preMinimizedRect;
|
|
985
818
|
win.preMinimizedRect = null;
|
|
986
819
|
}
|
|
987
820
|
win.state = "windowed";
|
|
988
|
-
win.zIndex =
|
|
821
|
+
win.zIndex = state.nextZIndex++;
|
|
989
822
|
},
|
|
990
823
|
/**
|
|
991
824
|
* Bring an already-registered window unconditionally into view — the
|
|
@@ -1006,13 +839,13 @@ var windowManagerSlice = createSlice2({
|
|
|
1006
839
|
*
|
|
1007
840
|
* Caller supplies viewport dimensions (reducers can't read `window`).
|
|
1008
841
|
*/
|
|
1009
|
-
revealWindow(
|
|
842
|
+
revealWindow(state, action) {
|
|
1010
843
|
const { id, viewportWidth, viewportHeight } = action.payload;
|
|
1011
|
-
const win =
|
|
844
|
+
const win = state.windows[id];
|
|
1012
845
|
if (!win) return;
|
|
1013
|
-
if (
|
|
846
|
+
if (state.windowsHidden) state.windowsHidden = false;
|
|
1014
847
|
if (win.popoutMode !== null) return;
|
|
1015
|
-
releaseTraySlot(
|
|
848
|
+
releaseTraySlot(state, win);
|
|
1016
849
|
if (win.state === "minimized") {
|
|
1017
850
|
if (win.preMinimizedRect) {
|
|
1018
851
|
win.windowed = win.preMinimizedRect;
|
|
@@ -1027,55 +860,55 @@ var windowManagerSlice = createSlice2({
|
|
|
1027
860
|
});
|
|
1028
861
|
if (!rectsEqual(win.windowed, clamped)) win.windowed = clamped;
|
|
1029
862
|
}
|
|
1030
|
-
win.zIndex =
|
|
863
|
+
win.zIndex = state.nextZIndex++;
|
|
1031
864
|
},
|
|
1032
865
|
/** Switch to maximized state. */
|
|
1033
|
-
maximizeWindow(
|
|
1034
|
-
const win =
|
|
866
|
+
maximizeWindow(state, action) {
|
|
867
|
+
const win = state.windows[action.payload];
|
|
1035
868
|
if (!win) return;
|
|
1036
|
-
releaseTraySlot(
|
|
869
|
+
releaseTraySlot(state, win);
|
|
1037
870
|
win.state = "maximized";
|
|
1038
|
-
win.zIndex =
|
|
871
|
+
win.zIndex = state.nextZIndex++;
|
|
1039
872
|
},
|
|
1040
873
|
/**
|
|
1041
874
|
* Minimize a window — parks it in the tray grid at the bottom of the
|
|
1042
875
|
* viewport. Caller must supply current viewport dimensions so the reducer
|
|
1043
876
|
* can compute the exact position without touching window/document.
|
|
1044
877
|
*/
|
|
1045
|
-
minimizeWindow(
|
|
878
|
+
minimizeWindow(state, action) {
|
|
1046
879
|
const { id, viewportWidth, viewportHeight } = action.payload;
|
|
1047
|
-
const win =
|
|
880
|
+
const win = state.windows[id];
|
|
1048
881
|
if (!win || win.state === "minimized") return;
|
|
1049
882
|
if (win.popoutMode !== null) return;
|
|
1050
883
|
win.preMinimizedRect = { ...win.windowed };
|
|
1051
|
-
const
|
|
1052
|
-
win.traySlot =
|
|
1053
|
-
|
|
1054
|
-
|
|
884
|
+
const slot = state.trayCount;
|
|
885
|
+
win.traySlot = slot;
|
|
886
|
+
state.trayCount += 1;
|
|
887
|
+
state.trayViewport = { width: viewportWidth, height: viewportHeight };
|
|
1055
888
|
win.state = "minimized";
|
|
1056
|
-
recomputeAllTrayRects(
|
|
889
|
+
recomputeAllTrayRects(state);
|
|
1057
890
|
},
|
|
1058
891
|
/**
|
|
1059
892
|
* Minimize ALL non-minimized, non-maximized windows in one shot.
|
|
1060
893
|
* Use for a "collapse all" button. Caller supplies viewport dimensions.
|
|
1061
894
|
*/
|
|
1062
|
-
minimizeAll(
|
|
895
|
+
minimizeAll(state, action) {
|
|
1063
896
|
const { viewportWidth, viewportHeight } = action.payload;
|
|
1064
|
-
|
|
1065
|
-
Object.values(
|
|
897
|
+
state.trayViewport = { width: viewportWidth, height: viewportHeight };
|
|
898
|
+
Object.values(state.windows).forEach((win) => {
|
|
1066
899
|
if (win.state !== "windowed") return;
|
|
1067
900
|
if (win.popoutMode !== null) return;
|
|
1068
901
|
win.preMinimizedRect = { ...win.windowed };
|
|
1069
|
-
const
|
|
1070
|
-
win.traySlot =
|
|
1071
|
-
|
|
902
|
+
const slot = state.trayCount;
|
|
903
|
+
win.traySlot = slot;
|
|
904
|
+
state.trayCount += 1;
|
|
1072
905
|
win.state = "minimized";
|
|
1073
906
|
});
|
|
1074
|
-
recomputeAllTrayRects(
|
|
907
|
+
recomputeAllTrayRects(state);
|
|
1075
908
|
},
|
|
1076
909
|
/** Update the windowed rect (called during drag or resize). */
|
|
1077
|
-
updateWindowRect(
|
|
1078
|
-
const win =
|
|
910
|
+
updateWindowRect(state, action) {
|
|
911
|
+
const win = state.windows[action.payload.id];
|
|
1079
912
|
if (!win) return;
|
|
1080
913
|
win.windowed = { ...win.windowed, ...action.payload.rect };
|
|
1081
914
|
},
|
|
@@ -1098,9 +931,9 @@ var windowManagerSlice = createSlice2({
|
|
|
1098
931
|
* `window.innerWidth` (consistent with `minimizeWindow` /
|
|
1099
932
|
* `arrangeActiveWindows` patterns).
|
|
1100
933
|
*/
|
|
1101
|
-
clampWindowRect(
|
|
934
|
+
clampWindowRect(state, action) {
|
|
1102
935
|
const { id, viewportWidth, viewportHeight } = action.payload;
|
|
1103
|
-
const win =
|
|
936
|
+
const win = state.windows[id];
|
|
1104
937
|
if (!win) return;
|
|
1105
938
|
if (win.state !== "windowed") return;
|
|
1106
939
|
if (win.popoutMode !== null) return;
|
|
@@ -1117,9 +950,9 @@ var windowManagerSlice = createSlice2({
|
|
|
1117
950
|
*
|
|
1118
951
|
* Mirrors `recomputeTrayPositions`'s coverage for minimized chips.
|
|
1119
952
|
*/
|
|
1120
|
-
clampAllWindowRects(
|
|
953
|
+
clampAllWindowRects(state, action) {
|
|
1121
954
|
const { viewportWidth, viewportHeight } = action.payload;
|
|
1122
|
-
Object.values(
|
|
955
|
+
Object.values(state.windows).forEach((win) => {
|
|
1123
956
|
if (win.state !== "windowed") return;
|
|
1124
957
|
if (win.popoutMode !== null) return;
|
|
1125
958
|
const clamped = clampRectToViewport(win.windowed, {
|
|
@@ -1130,9 +963,9 @@ var windowManagerSlice = createSlice2({
|
|
|
1130
963
|
});
|
|
1131
964
|
},
|
|
1132
965
|
/** Arranges all non-minimized windows globally */
|
|
1133
|
-
arrangeActiveWindows(
|
|
966
|
+
arrangeActiveWindows(state, action) {
|
|
1134
967
|
const { layout, viewportWidth, viewportHeight, dirX, dirY, primary } = action.payload;
|
|
1135
|
-
const eligibleWindows = Object.values(
|
|
968
|
+
const eligibleWindows = Object.values(state.windows).filter((w) => w.state === "windowed" && w.popoutMode === null).sort((a, b) => b.zIndex - a.zIndex).map((w) => w.id);
|
|
1136
969
|
if (eligibleWindows.length === 0) return;
|
|
1137
970
|
const updates = computeGlobalArrangement(
|
|
1138
971
|
layout,
|
|
@@ -1144,9 +977,9 @@ var windowManagerSlice = createSlice2({
|
|
|
1144
977
|
primary
|
|
1145
978
|
);
|
|
1146
979
|
updates.forEach(({ id, rect }) => {
|
|
1147
|
-
if (
|
|
1148
|
-
|
|
1149
|
-
...
|
|
980
|
+
if (state.windows[id]) {
|
|
981
|
+
state.windows[id].windowed = {
|
|
982
|
+
...state.windows[id].windowed,
|
|
1150
983
|
...rect
|
|
1151
984
|
};
|
|
1152
985
|
}
|
|
@@ -1157,27 +990,27 @@ var windowManagerSlice = createSlice2({
|
|
|
1157
990
|
* resize. Each window keeps its existing traySlot number — only x/y/w/h
|
|
1158
991
|
* are recalculated. No-op if nothing is minimized.
|
|
1159
992
|
*/
|
|
1160
|
-
recomputeTrayPositions(
|
|
993
|
+
recomputeTrayPositions(state, action) {
|
|
1161
994
|
const { viewportWidth, viewportHeight } = action.payload;
|
|
1162
995
|
if (!Number.isFinite(viewportWidth) || !Number.isFinite(viewportHeight) || viewportWidth <= 0 || viewportHeight <= 0) {
|
|
1163
996
|
return;
|
|
1164
997
|
}
|
|
1165
|
-
const minimized = Object.values(
|
|
998
|
+
const minimized = Object.values(state.windows).filter(
|
|
1166
999
|
(w) => w.state === "minimized" && w.traySlot !== null
|
|
1167
1000
|
);
|
|
1168
1001
|
if (minimized.length === 0) return;
|
|
1169
|
-
const tv =
|
|
1002
|
+
const tv = state.trayViewport;
|
|
1170
1003
|
if (!tv || tv.width !== viewportWidth || tv.height !== viewportHeight) {
|
|
1171
|
-
|
|
1004
|
+
state.trayViewport = { width: viewportWidth, height: viewportHeight };
|
|
1172
1005
|
}
|
|
1173
|
-
recomputeAllTrayRects(
|
|
1006
|
+
recomputeAllTrayRects(state);
|
|
1174
1007
|
},
|
|
1175
1008
|
/**
|
|
1176
1009
|
* Restore ALL minimized windows to their pre-minimized rects in one shot.
|
|
1177
1010
|
* Maximized windows are left alone — only minimized ones are affected.
|
|
1178
1011
|
*/
|
|
1179
|
-
restoreAll(
|
|
1180
|
-
Object.values(
|
|
1012
|
+
restoreAll(state) {
|
|
1013
|
+
Object.values(state.windows).forEach((win) => {
|
|
1181
1014
|
if (win.state !== "minimized") return;
|
|
1182
1015
|
if (win.preMinimizedRect) {
|
|
1183
1016
|
win.windowed = win.preMinimizedRect;
|
|
@@ -1185,44 +1018,44 @@ var windowManagerSlice = createSlice2({
|
|
|
1185
1018
|
}
|
|
1186
1019
|
win.traySlot = null;
|
|
1187
1020
|
win.state = "windowed";
|
|
1188
|
-
win.zIndex =
|
|
1021
|
+
win.zIndex = state.nextZIndex++;
|
|
1189
1022
|
});
|
|
1190
|
-
Object.values(
|
|
1023
|
+
Object.values(state.pendingRestores).forEach((session) => {
|
|
1191
1024
|
if (session.state !== "minimized") return;
|
|
1192
1025
|
session.state = "windowed";
|
|
1193
1026
|
session.traySlot = null;
|
|
1194
1027
|
session.renderRect = session.windowedRect;
|
|
1195
1028
|
});
|
|
1196
|
-
|
|
1197
|
-
|
|
1029
|
+
state.trayCount = 0;
|
|
1030
|
+
state.trayViewport = null;
|
|
1198
1031
|
},
|
|
1199
1032
|
/** Show or hide all windows (they stay mounted). */
|
|
1200
|
-
toggleWindowsHidden(
|
|
1201
|
-
|
|
1033
|
+
toggleWindowsHidden(state) {
|
|
1034
|
+
state.windowsHidden = !state.windowsHidden;
|
|
1202
1035
|
},
|
|
1203
1036
|
/** Move a minimized chip to a new tray slot (drag-within-tray). */
|
|
1204
|
-
moveTraySlot(
|
|
1037
|
+
moveTraySlot(state, action) {
|
|
1205
1038
|
const { id, toSlot } = action.payload;
|
|
1206
|
-
const win =
|
|
1039
|
+
const win = state.windows[id];
|
|
1207
1040
|
if (!win || win.traySlot === null) return;
|
|
1208
1041
|
const fromSlot = win.traySlot;
|
|
1209
1042
|
const boundedSlot = Math.min(
|
|
1210
1043
|
Math.max(0, Math.floor(toSlot)),
|
|
1211
|
-
Math.max(0,
|
|
1044
|
+
Math.max(0, state.trayCount - 1)
|
|
1212
1045
|
);
|
|
1213
1046
|
if (fromSlot === boundedSlot) return;
|
|
1214
1047
|
const rectBySlot = /* @__PURE__ */ new Map();
|
|
1215
|
-
Object.values(
|
|
1048
|
+
Object.values(state.windows).forEach((entry) => {
|
|
1216
1049
|
if (entry.traySlot !== null) {
|
|
1217
1050
|
rectBySlot.set(entry.traySlot, { ...entry.windowed });
|
|
1218
1051
|
}
|
|
1219
1052
|
});
|
|
1220
|
-
Object.values(
|
|
1053
|
+
Object.values(state.pendingRestores).forEach((session) => {
|
|
1221
1054
|
if (session.traySlot !== null) {
|
|
1222
1055
|
rectBySlot.set(session.traySlot, { ...session.renderRect });
|
|
1223
1056
|
}
|
|
1224
1057
|
});
|
|
1225
|
-
Object.values(
|
|
1058
|
+
Object.values(state.windows).forEach((w) => {
|
|
1226
1059
|
if (w.id === id || w.traySlot === null) return;
|
|
1227
1060
|
if (fromSlot < boundedSlot && w.traySlot > fromSlot && w.traySlot <= boundedSlot) {
|
|
1228
1061
|
w.traySlot -= 1;
|
|
@@ -1230,7 +1063,7 @@ var windowManagerSlice = createSlice2({
|
|
|
1230
1063
|
w.traySlot += 1;
|
|
1231
1064
|
}
|
|
1232
1065
|
});
|
|
1233
|
-
Object.values(
|
|
1066
|
+
Object.values(state.pendingRestores).forEach((session) => {
|
|
1234
1067
|
if (session.traySlot === null) return;
|
|
1235
1068
|
if (fromSlot < boundedSlot && session.traySlot > fromSlot && session.traySlot <= boundedSlot) {
|
|
1236
1069
|
session.traySlot -= 1;
|
|
@@ -1239,17 +1072,17 @@ var windowManagerSlice = createSlice2({
|
|
|
1239
1072
|
}
|
|
1240
1073
|
});
|
|
1241
1074
|
win.traySlot = boundedSlot;
|
|
1242
|
-
Object.values(
|
|
1075
|
+
Object.values(state.windows).forEach((entry) => {
|
|
1243
1076
|
if (entry.traySlot === null) return;
|
|
1244
1077
|
const nextRect = rectBySlot.get(entry.traySlot);
|
|
1245
1078
|
if (nextRect) entry.windowed = nextRect;
|
|
1246
1079
|
});
|
|
1247
|
-
Object.values(
|
|
1080
|
+
Object.values(state.pendingRestores).forEach((session) => {
|
|
1248
1081
|
if (session.traySlot === null) return;
|
|
1249
1082
|
const nextRect = rectBySlot.get(session.traySlot);
|
|
1250
1083
|
if (nextRect) session.renderRect = nextRect;
|
|
1251
1084
|
});
|
|
1252
|
-
recomputeAllTrayRects(
|
|
1085
|
+
recomputeAllTrayRects(state);
|
|
1253
1086
|
},
|
|
1254
1087
|
/**
|
|
1255
1088
|
* Transition a window into popped-out mode.
|
|
@@ -1268,15 +1101,15 @@ var windowManagerSlice = createSlice2({
|
|
|
1268
1101
|
* before requesting `mode: "pip"`. This reducer is defense-in-depth and
|
|
1269
1102
|
* silently no-ops if a different window already holds the PiP slot.
|
|
1270
1103
|
*/
|
|
1271
|
-
popOutWindow(
|
|
1104
|
+
popOutWindow(state, action) {
|
|
1272
1105
|
const { id, mode } = action.payload;
|
|
1273
|
-
const win =
|
|
1106
|
+
const win = state.windows[id];
|
|
1274
1107
|
if (!win) return;
|
|
1275
|
-
if (mode === "pip" &&
|
|
1108
|
+
if (mode === "pip" && state.activePipWindowId !== null && state.activePipWindowId !== id) {
|
|
1276
1109
|
return;
|
|
1277
1110
|
}
|
|
1278
1111
|
if (win.traySlot !== null) {
|
|
1279
|
-
releaseTraySlot(
|
|
1112
|
+
releaseTraySlot(state, win);
|
|
1280
1113
|
if (win.preMinimizedRect) {
|
|
1281
1114
|
win.windowed = win.preMinimizedRect;
|
|
1282
1115
|
win.preMinimizedRect = null;
|
|
@@ -1288,10 +1121,10 @@ var windowManagerSlice = createSlice2({
|
|
|
1288
1121
|
}
|
|
1289
1122
|
win.popoutMode = mode;
|
|
1290
1123
|
if (mode === "pip") {
|
|
1291
|
-
|
|
1124
|
+
state.activePipWindowId = id;
|
|
1292
1125
|
}
|
|
1293
|
-
if (
|
|
1294
|
-
|
|
1126
|
+
if (state.popoutCandidateId === id) {
|
|
1127
|
+
state.popoutCandidateId = null;
|
|
1295
1128
|
}
|
|
1296
1129
|
},
|
|
1297
1130
|
/**
|
|
@@ -1302,12 +1135,12 @@ var windowManagerSlice = createSlice2({
|
|
|
1302
1135
|
* `popoutMode`, releases the PiP slot if held, and bumps z-index.
|
|
1303
1136
|
* Caller is responsible for closing the actual browser popout window.
|
|
1304
1137
|
*/
|
|
1305
|
-
dockWindow(
|
|
1138
|
+
dockWindow(state, action) {
|
|
1306
1139
|
const { id, viewportWidth, viewportHeight } = action.payload;
|
|
1307
|
-
const win =
|
|
1140
|
+
const win = state.windows[id];
|
|
1308
1141
|
if (!win || win.popoutMode === null) return;
|
|
1309
|
-
if (
|
|
1310
|
-
|
|
1142
|
+
if (state.activePipWindowId === win.id) {
|
|
1143
|
+
state.activePipWindowId = null;
|
|
1311
1144
|
}
|
|
1312
1145
|
const savedRect = win.prePopoutRect ?? win.windowed;
|
|
1313
1146
|
const centered = centerRectInViewport(savedRect, {
|
|
@@ -1317,7 +1150,7 @@ var windowManagerSlice = createSlice2({
|
|
|
1317
1150
|
win.windowed = centered;
|
|
1318
1151
|
win.prePopoutRect = null;
|
|
1319
1152
|
win.popoutMode = null;
|
|
1320
|
-
win.zIndex =
|
|
1153
|
+
win.zIndex = state.nextZIndex++;
|
|
1321
1154
|
},
|
|
1322
1155
|
/**
|
|
1323
1156
|
* Set or clear the drag-out candidate window. Used purely for visual
|
|
@@ -1325,29 +1158,29 @@ var windowManagerSlice = createSlice2({
|
|
|
1325
1158
|
* "Release to pop out" outline. Cleared on every pointerup regardless
|
|
1326
1159
|
* of whether popout actually fires.
|
|
1327
1160
|
*/
|
|
1328
|
-
setPopoutCandidate(
|
|
1329
|
-
|
|
1161
|
+
setPopoutCandidate(state, action) {
|
|
1162
|
+
state.popoutCandidateId = action.payload.id;
|
|
1330
1163
|
},
|
|
1331
1164
|
/** Restore window geometry and state from localStorage */
|
|
1332
|
-
restoreWindowState(
|
|
1165
|
+
restoreWindowState(state, action) {
|
|
1333
1166
|
const restored = action.payload;
|
|
1334
|
-
let maxZ =
|
|
1167
|
+
let maxZ = state.nextZIndex;
|
|
1335
1168
|
Object.entries(restored).forEach(([id, win]) => {
|
|
1336
|
-
if (!
|
|
1169
|
+
if (!state.windows[id]) {
|
|
1337
1170
|
return;
|
|
1338
1171
|
}
|
|
1339
|
-
|
|
1340
|
-
...
|
|
1172
|
+
state.windows[id] = {
|
|
1173
|
+
...state.windows[id],
|
|
1341
1174
|
...win,
|
|
1342
1175
|
popoutMode: null,
|
|
1343
1176
|
prePopoutRect: null
|
|
1344
1177
|
};
|
|
1345
1178
|
if (win.zIndex >= maxZ) maxZ = win.zIndex + 1;
|
|
1346
1179
|
});
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1180
|
+
state.nextZIndex = Math.max(state.nextZIndex, maxZ);
|
|
1181
|
+
state.activePipWindowId = null;
|
|
1182
|
+
state.popoutCandidateId = null;
|
|
1183
|
+
state.trayCount = Object.values(state.windows).filter(
|
|
1351
1184
|
(w) => w.traySlot !== null
|
|
1352
1185
|
).length;
|
|
1353
1186
|
}
|
|
@@ -1355,7 +1188,7 @@ var windowManagerSlice = createSlice2({
|
|
|
1355
1188
|
extraReducers: (builder) => {
|
|
1356
1189
|
builder.addMatcher(
|
|
1357
1190
|
(action) => action.type === "overlays/closeOverlay",
|
|
1358
|
-
(
|
|
1191
|
+
(state, action) => {
|
|
1359
1192
|
const payload = action.payload;
|
|
1360
1193
|
if (!payload || typeof payload !== "object") return;
|
|
1361
1194
|
const overlayId = payload.overlayId;
|
|
@@ -1363,20 +1196,20 @@ var windowManagerSlice = createSlice2({
|
|
|
1363
1196
|
if (typeof overlayId !== "string" || typeof instanceId !== "string") {
|
|
1364
1197
|
return;
|
|
1365
1198
|
}
|
|
1366
|
-
const
|
|
1199
|
+
const pending = Object.values(state.pendingRestores).find(
|
|
1367
1200
|
(session) => session.overlayId === overlayId && session.instanceId === instanceId
|
|
1368
1201
|
);
|
|
1369
|
-
const hasMatchingLive =
|
|
1370
|
-
|
|
1202
|
+
const hasMatchingLive = pending ? hasMatchingLiveTrayReservation(
|
|
1203
|
+
state,
|
|
1371
1204
|
overlayId,
|
|
1372
1205
|
instanceId,
|
|
1373
|
-
|
|
1206
|
+
pending.traySlot
|
|
1374
1207
|
) : false;
|
|
1375
|
-
if (!hasMatchingLive &&
|
|
1376
|
-
compactReservedTraySlot(
|
|
1208
|
+
if (!hasMatchingLive && pending?.traySlot != null) {
|
|
1209
|
+
compactReservedTraySlot(state, pending.traySlot, pending.renderRect);
|
|
1377
1210
|
}
|
|
1378
|
-
if (
|
|
1379
|
-
Object.values(
|
|
1211
|
+
if (pending) delete state.pendingRestores[pending.sessionKey];
|
|
1212
|
+
Object.values(state.windows).forEach((entry) => {
|
|
1380
1213
|
if (entry.persistence?.overlayId === overlayId && entry.persistence.instanceId === instanceId) {
|
|
1381
1214
|
entry.persistence.closing = true;
|
|
1382
1215
|
}
|
|
@@ -1385,10 +1218,10 @@ var windowManagerSlice = createSlice2({
|
|
|
1385
1218
|
);
|
|
1386
1219
|
builder.addMatcher(
|
|
1387
1220
|
(action) => action.type === "overlays/closeAllOverlays",
|
|
1388
|
-
(
|
|
1389
|
-
Object.values(
|
|
1221
|
+
(state) => {
|
|
1222
|
+
Object.values(state.pendingRestores).filter(
|
|
1390
1223
|
(session) => session.traySlot !== null && !hasMatchingLiveTrayReservation(
|
|
1391
|
-
|
|
1224
|
+
state,
|
|
1392
1225
|
session.overlayId,
|
|
1393
1226
|
session.instanceId,
|
|
1394
1227
|
session.traySlot
|
|
@@ -1396,27 +1229,27 @@ var windowManagerSlice = createSlice2({
|
|
|
1396
1229
|
).sort((a, b) => (b.traySlot ?? -1) - (a.traySlot ?? -1)).forEach((session) => {
|
|
1397
1230
|
if (session.traySlot !== null) {
|
|
1398
1231
|
compactReservedTraySlot(
|
|
1399
|
-
|
|
1232
|
+
state,
|
|
1400
1233
|
session.traySlot,
|
|
1401
1234
|
session.renderRect
|
|
1402
1235
|
);
|
|
1403
1236
|
}
|
|
1404
1237
|
});
|
|
1405
|
-
|
|
1406
|
-
Object.values(
|
|
1238
|
+
state.pendingRestores = {};
|
|
1239
|
+
Object.values(state.windows).forEach((entry) => {
|
|
1407
1240
|
if (entry.persistence) entry.persistence.closing = true;
|
|
1408
1241
|
});
|
|
1409
1242
|
}
|
|
1410
1243
|
);
|
|
1411
1244
|
builder.addMatcher(
|
|
1412
1245
|
(action) => action.type === "overlays/closeAllInstancesOfOverlay",
|
|
1413
|
-
(
|
|
1246
|
+
(state, action) => {
|
|
1414
1247
|
const payload = action.payload;
|
|
1415
1248
|
const overlayId = payload && typeof payload === "object" && "overlayId" in payload ? payload.overlayId : null;
|
|
1416
1249
|
if (typeof overlayId !== "string") return;
|
|
1417
|
-
Object.values(
|
|
1250
|
+
Object.values(state.pendingRestores).filter(
|
|
1418
1251
|
(session) => session.overlayId === overlayId && session.traySlot !== null && !hasMatchingLiveTrayReservation(
|
|
1419
|
-
|
|
1252
|
+
state,
|
|
1420
1253
|
session.overlayId,
|
|
1421
1254
|
session.instanceId,
|
|
1422
1255
|
session.traySlot
|
|
@@ -1424,17 +1257,17 @@ var windowManagerSlice = createSlice2({
|
|
|
1424
1257
|
).sort((a, b) => (b.traySlot ?? -1) - (a.traySlot ?? -1)).forEach((session) => {
|
|
1425
1258
|
if (session.traySlot !== null) {
|
|
1426
1259
|
compactReservedTraySlot(
|
|
1427
|
-
|
|
1260
|
+
state,
|
|
1428
1261
|
session.traySlot,
|
|
1429
1262
|
session.renderRect
|
|
1430
1263
|
);
|
|
1431
1264
|
}
|
|
1432
1265
|
});
|
|
1433
|
-
Object.entries(
|
|
1266
|
+
Object.entries(state.pendingRestores).forEach(([key, session]) => {
|
|
1434
1267
|
if (session.overlayId === overlayId)
|
|
1435
|
-
delete
|
|
1268
|
+
delete state.pendingRestores[key];
|
|
1436
1269
|
});
|
|
1437
|
-
Object.values(
|
|
1270
|
+
Object.values(state.windows).forEach((entry) => {
|
|
1438
1271
|
if (entry.persistence?.overlayId === overlayId) {
|
|
1439
1272
|
entry.persistence.closing = true;
|
|
1440
1273
|
}
|
|
@@ -1448,19 +1281,19 @@ var {
|
|
|
1448
1281
|
releaseTransientWindow,
|
|
1449
1282
|
registerWindow,
|
|
1450
1283
|
unregisterWindow,
|
|
1451
|
-
focusWindow
|
|
1452
|
-
restoreWindow
|
|
1453
|
-
revealWindow
|
|
1284
|
+
focusWindow,
|
|
1285
|
+
restoreWindow,
|
|
1286
|
+
revealWindow,
|
|
1454
1287
|
maximizeWindow,
|
|
1455
1288
|
minimizeWindow,
|
|
1456
|
-
minimizeAll
|
|
1457
|
-
restoreAll
|
|
1289
|
+
minimizeAll,
|
|
1290
|
+
restoreAll,
|
|
1458
1291
|
recomputeTrayPositions,
|
|
1459
|
-
updateWindowRect
|
|
1292
|
+
updateWindowRect,
|
|
1460
1293
|
updateWindowTitle,
|
|
1461
|
-
toggleWindowsHidden
|
|
1294
|
+
toggleWindowsHidden,
|
|
1462
1295
|
moveTraySlot,
|
|
1463
|
-
arrangeActiveWindows
|
|
1296
|
+
arrangeActiveWindows,
|
|
1464
1297
|
popOutWindow,
|
|
1465
1298
|
dockWindow,
|
|
1466
1299
|
setPopoutCandidate,
|
|
@@ -1474,17 +1307,17 @@ var {
|
|
|
1474
1307
|
markWindowClosing,
|
|
1475
1308
|
clearWindowPersistenceState
|
|
1476
1309
|
} = windowManagerSlice.actions;
|
|
1477
|
-
var selectWindowsMap = (
|
|
1478
|
-
var selectPendingWindowRestores = (
|
|
1479
|
-
var selectWindowPersistence = (id) => (
|
|
1480
|
-
var selectWindow = (id) => (
|
|
1481
|
-
var selectWindowState = (id) => (
|
|
1482
|
-
var selectWindowRect = (id) => (
|
|
1483
|
-
var selectWindowZIndex = (id) => (
|
|
1484
|
-
var selectTransientZIndex = (id) => (
|
|
1485
|
-
var selectWindowTitle = (id) => (
|
|
1310
|
+
var selectWindowsMap = (state) => state.windowManager.windows;
|
|
1311
|
+
var selectPendingWindowRestores = (state) => state.windowManager.pendingRestores;
|
|
1312
|
+
var selectWindowPersistence = (id) => (state) => state.windowManager.windows[id]?.persistence;
|
|
1313
|
+
var selectWindow = (id) => (state) => state.windowManager.windows[id];
|
|
1314
|
+
var selectWindowState = (id) => (state) => state.windowManager.windows[id]?.state;
|
|
1315
|
+
var selectWindowRect = (id) => (state) => state.windowManager.windows[id]?.windowed;
|
|
1316
|
+
var selectWindowZIndex = (id) => (state) => state.windowManager.windows[id]?.zIndex ?? BASE_Z;
|
|
1317
|
+
var selectTransientZIndex = (id) => (state) => state.windowManager.transientZ[id] ?? BASE_Z;
|
|
1318
|
+
var selectWindowTitle = (id) => (state) => state.windowManager.windows[id]?.title ?? id;
|
|
1486
1319
|
var selectTraySlotWidth = () => TRAY_SLOT_WIDTH;
|
|
1487
|
-
var selectWindowsHidden = (
|
|
1320
|
+
var selectWindowsHidden = (state) => state.windowManager.windowsHidden;
|
|
1488
1321
|
var selectTrayWindows = createSelector(
|
|
1489
1322
|
[selectWindowsMap],
|
|
1490
1323
|
(windows) => Object.values(windows).filter((w) => w.state === "minimized").sort((a, b) => (a.traySlot ?? 0) - (b.traySlot ?? 0))
|
|
@@ -1500,11 +1333,11 @@ var selectAllMinimized = createSelector(
|
|
|
1500
1333
|
return wins.length > 0 && wins.every((w) => w.state === "minimized");
|
|
1501
1334
|
}
|
|
1502
1335
|
);
|
|
1503
|
-
var selectPopoutMode = (id) => (
|
|
1504
|
-
var selectIsPoppedOut = (id) => (
|
|
1505
|
-
var selectActivePipWindowId = (
|
|
1506
|
-
var selectPopoutCandidateId = (
|
|
1507
|
-
var selectPrePopoutRect = (id) => (
|
|
1336
|
+
var selectPopoutMode = (id) => (state) => state.windowManager.windows[id]?.popoutMode ?? null;
|
|
1337
|
+
var selectIsPoppedOut = (id) => (state) => (state.windowManager.windows[id]?.popoutMode ?? null) !== null;
|
|
1338
|
+
var selectActivePipWindowId = (state) => state.windowManager.activePipWindowId;
|
|
1339
|
+
var selectPopoutCandidateId = (state) => state.windowManager.popoutCandidateId;
|
|
1340
|
+
var selectPrePopoutRect = (id) => (state) => state.windowManager.windows[id]?.prePopoutRect ?? null;
|
|
1508
1341
|
var selectDockedWindows = createSelector(
|
|
1509
1342
|
[selectWindowsMap],
|
|
1510
1343
|
(windows) => Object.values(windows).filter((w) => w.popoutMode === null).sort((a, b) => b.zIndex - a.zIndex)
|
|
@@ -1521,23 +1354,23 @@ var urlSyncSlice = createSlice3({
|
|
|
1521
1354
|
name: "urlSync",
|
|
1522
1355
|
initialState: initialState3,
|
|
1523
1356
|
reducers: {
|
|
1524
|
-
setHydrated: (
|
|
1525
|
-
|
|
1357
|
+
setHydrated: (state) => {
|
|
1358
|
+
state.isHydrated = true;
|
|
1526
1359
|
},
|
|
1527
|
-
registerSyncEntry: (
|
|
1360
|
+
registerSyncEntry: (state, action) => {
|
|
1528
1361
|
const key = `${action.payload.typeKey}:${action.payload.instanceId}`;
|
|
1529
|
-
|
|
1362
|
+
state.entries[key] = action.payload;
|
|
1530
1363
|
},
|
|
1531
|
-
unregisterSyncEntry: (
|
|
1364
|
+
unregisterSyncEntry: (state, action) => {
|
|
1532
1365
|
const key = `${action.payload.typeKey}:${action.payload.instanceId}`;
|
|
1533
|
-
delete
|
|
1366
|
+
delete state.entries[key];
|
|
1534
1367
|
}
|
|
1535
1368
|
}
|
|
1536
1369
|
});
|
|
1537
1370
|
var linksReducer = urlSyncSlice.reducer;
|
|
1538
|
-
var { setHydrated, registerSyncEntry
|
|
1539
|
-
var selectUrlSyncEntries = (
|
|
1540
|
-
var selectIsUrlHydrated = (
|
|
1371
|
+
var { setHydrated, registerSyncEntry, unregisterSyncEntry } = urlSyncSlice.actions;
|
|
1372
|
+
var selectUrlSyncEntries = (state) => state.urlSync.entries;
|
|
1373
|
+
var selectIsUrlHydrated = (state) => state.urlSync.isHydrated;
|
|
1541
1374
|
|
|
1542
1375
|
// src/core/overlayStateSlice.ts
|
|
1543
1376
|
import { createSlice as createSlice4 } from "@reduxjs/toolkit";
|
|
@@ -1546,319 +1379,39 @@ var overlayStateSlice = createSlice4({
|
|
|
1546
1379
|
name: "overlayState",
|
|
1547
1380
|
initialState: initialState4,
|
|
1548
1381
|
reducers: {
|
|
1549
|
-
setOverlayStateValue(
|
|
1382
|
+
setOverlayStateValue(state, action) {
|
|
1550
1383
|
const { key, name, value } = action.payload;
|
|
1551
|
-
const entry =
|
|
1384
|
+
const entry = state.entries[key] ??= { values: {}, updatedAt: 0 };
|
|
1552
1385
|
entry.values[name] = value;
|
|
1553
1386
|
entry.updatedAt = Date.now();
|
|
1554
1387
|
},
|
|
1555
|
-
replaceOverlayState(
|
|
1388
|
+
replaceOverlayState(state, action) {
|
|
1556
1389
|
const { key, values } = action.payload;
|
|
1557
|
-
|
|
1390
|
+
state.entries[key] = { values: { ...values }, updatedAt: Date.now() };
|
|
1558
1391
|
},
|
|
1559
|
-
clearOverlayState(
|
|
1560
|
-
delete
|
|
1392
|
+
clearOverlayState(state, action) {
|
|
1393
|
+
delete state.entries[action.payload.key];
|
|
1561
1394
|
},
|
|
1562
|
-
hydrateOverlayState(
|
|
1395
|
+
hydrateOverlayState(state, action) {
|
|
1563
1396
|
const now = Date.now();
|
|
1564
1397
|
for (const [key, entry] of Object.entries(action.payload.entries)) {
|
|
1565
|
-
|
|
1398
|
+
state.entries[key] = { values: { ...entry.values }, updatedAt: entry.updatedAt ?? now };
|
|
1566
1399
|
}
|
|
1567
1400
|
}
|
|
1568
1401
|
}
|
|
1569
1402
|
});
|
|
1570
1403
|
var overlayStateReducer = overlayStateSlice.reducer;
|
|
1571
|
-
var { setOverlayStateValue
|
|
1404
|
+
var { setOverlayStateValue, replaceOverlayState, clearOverlayState, hydrateOverlayState } = overlayStateSlice.actions;
|
|
1572
1405
|
var EMPTY_VALUES = Object.freeze({});
|
|
1573
|
-
var selectOverlayStateValue = (
|
|
1574
|
-
var selectOverlayStateFor = (
|
|
1406
|
+
var selectOverlayStateValue = (state, key, name) => state.overlayState.entries[key]?.values[name];
|
|
1407
|
+
var selectOverlayStateFor = (state, key) => state.overlayState.entries[key]?.values ?? EMPTY_VALUES;
|
|
1575
1408
|
|
|
1576
1409
|
// src/core/store.ts
|
|
1577
1410
|
import { combineReducers, configureStore } from "@reduxjs/toolkit";
|
|
1578
1411
|
|
|
1579
1412
|
// src/core/middleware/closeLifecycle.ts
|
|
1580
|
-
import { globalSlot
|
|
1581
|
-
|
|
1582
|
-
// src/open/ids.ts
|
|
1583
|
-
function newHandleId() {
|
|
1584
|
-
const c = typeof globalThis.crypto === "undefined" ? void 0 : globalThis.crypto;
|
|
1585
|
-
if (c && typeof c.randomUUID === "function") return c.randomUUID();
|
|
1586
|
-
const bytes = new Uint8Array(16);
|
|
1587
|
-
if (c && typeof c.getRandomValues === "function") {
|
|
1588
|
-
c.getRandomValues(bytes);
|
|
1589
|
-
} else {
|
|
1590
|
-
for (let i = 0; i < 16; i += 1) bytes[i] = Math.floor(Math.random() * 256);
|
|
1591
|
-
}
|
|
1592
|
-
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
1593
|
-
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
1594
|
-
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
1595
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
// src/handles/slot.ts
|
|
1599
|
-
var HANDLES_SLOT = "ai-matrx.summon.handles";
|
|
1600
|
-
|
|
1601
|
-
// src/open/handleEntries.ts
|
|
1602
|
-
import { globalSlot as globalSlot3 } from "@ai-matrx/kit/global-slot";
|
|
1603
|
-
var handlesState = () => globalSlot3(HANDLES_SLOT, () => ({
|
|
1604
|
-
callbacks: /* @__PURE__ */ new Map(),
|
|
1605
|
-
groups: /* @__PURE__ */ new Map(),
|
|
1606
|
-
owners: /* @__PURE__ */ new Map(),
|
|
1607
|
-
registryListeners: /* @__PURE__ */ new Set()
|
|
1608
|
-
}));
|
|
1609
|
-
function notifyHandlesRegistry() {
|
|
1610
|
-
for (const listener of [...handlesState().registryListeners]) listener();
|
|
1611
|
-
}
|
|
1612
|
-
function deleteHandleEntry(id, notify = true) {
|
|
1613
|
-
const s = handlesState();
|
|
1614
|
-
const entry = s.callbacks.get(id);
|
|
1615
|
-
if (!entry) return;
|
|
1616
|
-
s.callbacks.delete(id);
|
|
1617
|
-
if (entry.groupId !== void 0) {
|
|
1618
|
-
const group = s.groups.get(entry.groupId);
|
|
1619
|
-
group?.delete(id);
|
|
1620
|
-
if (group?.size === 0) s.groups.delete(entry.groupId);
|
|
1621
|
-
}
|
|
1622
|
-
if (entry.owner !== void 0) {
|
|
1623
|
-
const owned = s.owners.get(entry.owner);
|
|
1624
|
-
owned?.delete(id);
|
|
1625
|
-
if (owned?.size === 0) s.owners.delete(entry.owner);
|
|
1626
|
-
}
|
|
1627
|
-
if (notify) notifyHandlesRegistry();
|
|
1628
|
-
entry.onRemove?.();
|
|
1629
|
-
}
|
|
1630
|
-
function registerHandleEntry(slot2, options = {}) {
|
|
1631
|
-
const s = handlesState();
|
|
1632
|
-
const id = options.id ?? newHandleId();
|
|
1633
|
-
if (s.callbacks.has(id)) deleteHandleEntry(id, false);
|
|
1634
|
-
const entry = { callback: slot2 };
|
|
1635
|
-
if (options.context !== void 0) entry.context = options.context;
|
|
1636
|
-
if (options.groupId !== void 0) entry.groupId = options.groupId;
|
|
1637
|
-
if (options.owner !== void 0) entry.owner = options.owner;
|
|
1638
|
-
if (options.onRemove !== void 0) entry.onRemove = options.onRemove;
|
|
1639
|
-
s.callbacks.set(id, entry);
|
|
1640
|
-
if (options.groupId !== void 0) {
|
|
1641
|
-
const group = s.groups.get(options.groupId) ?? /* @__PURE__ */ new Set();
|
|
1642
|
-
group.add(id);
|
|
1643
|
-
s.groups.set(options.groupId, group);
|
|
1644
|
-
}
|
|
1645
|
-
if (options.owner !== void 0) {
|
|
1646
|
-
const owned = s.owners.get(options.owner) ?? /* @__PURE__ */ new Set();
|
|
1647
|
-
owned.add(id);
|
|
1648
|
-
s.owners.set(options.owner, owned);
|
|
1649
|
-
}
|
|
1650
|
-
notifyHandlesRegistry();
|
|
1651
|
-
return id;
|
|
1652
|
-
}
|
|
1653
|
-
function removeHandleGroup(groupId) {
|
|
1654
|
-
const s = handlesState();
|
|
1655
|
-
const group = s.groups.get(groupId);
|
|
1656
|
-
if (!group) return;
|
|
1657
|
-
s.groups.delete(groupId);
|
|
1658
|
-
for (const id of [...group]) deleteHandleEntry(id, false);
|
|
1659
|
-
notifyHandlesRegistry();
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
// src/handles/callbackManager.ts
|
|
1663
|
-
var handlesState2 = () => handlesState();
|
|
1664
|
-
function invoke(slot2, data, context) {
|
|
1665
|
-
if (typeof slot2 !== "function") return void 0;
|
|
1666
|
-
return slot2(data, context);
|
|
1667
|
-
}
|
|
1668
|
-
function invokeListener(listener, data, context) {
|
|
1669
|
-
return listener(data, context);
|
|
1670
|
-
}
|
|
1671
|
-
var CallbackManager = class {
|
|
1672
|
-
get s() {
|
|
1673
|
-
return handlesState2();
|
|
1674
|
-
}
|
|
1675
|
-
/**
|
|
1676
|
-
* Observe the registry itself: `listener` runs after any entry is added or removed. This lets a
|
|
1677
|
-
* view that resolves ids with `get` re-render when an id goes away (`useSyncExternalStore`).
|
|
1678
|
-
*/
|
|
1679
|
-
subscribeToRegistry(listener) {
|
|
1680
|
-
const listeners = this.s.registryListeners;
|
|
1681
|
-
listeners.add(listener);
|
|
1682
|
-
return () => {
|
|
1683
|
-
listeners.delete(listener);
|
|
1684
|
-
};
|
|
1685
|
-
}
|
|
1686
|
-
notifyRegistry() {
|
|
1687
|
-
notifyHandlesRegistry();
|
|
1688
|
-
}
|
|
1689
|
-
/** Register a callback; returns its id. */
|
|
1690
|
-
register(callback) {
|
|
1691
|
-
return this.registerEntry(callback, {});
|
|
1692
|
-
}
|
|
1693
|
-
/** Register with optional context, group and owner. */
|
|
1694
|
-
registerWithContext(callback, options = {}) {
|
|
1695
|
-
return this.registerEntry(callback, options);
|
|
1696
|
-
}
|
|
1697
|
-
/** @internal The one insertion path (typed helpers pass a fixed id and a removal hook). */
|
|
1698
|
-
registerEntry(slot2, options) {
|
|
1699
|
-
return registerHandleEntry(slot2, options);
|
|
1700
|
-
}
|
|
1701
|
-
/** Subscribe to results for a callback id. */
|
|
1702
|
-
subscribe(callbackId, listener) {
|
|
1703
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1704
|
-
if (!entry) return false;
|
|
1705
|
-
(entry.listeners ??= []).push(listener);
|
|
1706
|
-
return true;
|
|
1707
|
-
}
|
|
1708
|
-
/** Unsubscribe a listener from a callback id. */
|
|
1709
|
-
unsubscribe(callbackId, listener) {
|
|
1710
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1711
|
-
if (!entry || !entry.listeners) return false;
|
|
1712
|
-
const index = entry.listeners.indexOf(listener);
|
|
1713
|
-
if (index === -1) return false;
|
|
1714
|
-
entry.listeners.splice(index, 1);
|
|
1715
|
-
return true;
|
|
1716
|
-
}
|
|
1717
|
-
/** Run a callback once, notify its listeners, then remove it. */
|
|
1718
|
-
trigger(callbackId, data) {
|
|
1719
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1720
|
-
if (!entry) return;
|
|
1721
|
-
void invoke(entry.callback, data);
|
|
1722
|
-
if (entry.listeners && entry.listeners.length > 0) {
|
|
1723
|
-
for (const listener of [...entry.listeners]) void invokeListener(listener, data);
|
|
1724
|
-
}
|
|
1725
|
-
this.deleteEntry(callbackId, true);
|
|
1726
|
-
}
|
|
1727
|
-
/** Trigger with merged context and progress; removes unless `removeAfterTrigger: false`. */
|
|
1728
|
-
triggerWithContext(callbackId, data, options) {
|
|
1729
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1730
|
-
if (!entry) return;
|
|
1731
|
-
const mergedContext = {
|
|
1732
|
-
...entry.context,
|
|
1733
|
-
...options?.context,
|
|
1734
|
-
...options?.progress && { progress: options.progress }
|
|
1735
|
-
};
|
|
1736
|
-
void invoke(entry.callback, data, mergedContext);
|
|
1737
|
-
if (entry.listeners && entry.listeners.length > 0) {
|
|
1738
|
-
for (const listener of [...entry.listeners]) void invokeListener(listener, data, mergedContext);
|
|
1739
|
-
}
|
|
1740
|
-
if (options?.removeAfterTrigger !== false) this.deleteEntry(callbackId, true);
|
|
1741
|
-
}
|
|
1742
|
-
/** Trigger every callback in a group. */
|
|
1743
|
-
triggerGroup(groupId, data, options) {
|
|
1744
|
-
const group = this.s.groups.get(groupId);
|
|
1745
|
-
if (!group) return;
|
|
1746
|
-
for (const callbackId of [...group]) this.triggerWithContext(callbackId, data, options);
|
|
1747
|
-
if (options?.removeAfterTrigger !== false) this.s.groups.delete(groupId);
|
|
1748
|
-
}
|
|
1749
|
-
/**
|
|
1750
|
-
* Run the one durable command registered for a group. A command is retained on rejection so its
|
|
1751
|
-
* caller can retry, and is removed only after its promise settles successfully.
|
|
1752
|
-
*/
|
|
1753
|
-
async triggerGroupCommand(groupId, data, options) {
|
|
1754
|
-
const group = this.s.groups.get(groupId);
|
|
1755
|
-
const callbackIds = group ? [...group] : [];
|
|
1756
|
-
const callbackId = callbackIds[0];
|
|
1757
|
-
if (callbackIds.length !== 1 || callbackId === void 0) {
|
|
1758
|
-
throw new Error(`Expected exactly one command callback for group "${groupId}", found ${callbackIds.length}`);
|
|
1759
|
-
}
|
|
1760
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1761
|
-
if (!entry) throw new Error(`Command callback "${callbackId}" is no longer available`);
|
|
1762
|
-
const mergedContext = { ...entry.context, ...options?.context };
|
|
1763
|
-
await invoke(entry.callback, data, mergedContext);
|
|
1764
|
-
for (const listener of entry.listeners ?? []) {
|
|
1765
|
-
try {
|
|
1766
|
-
await invokeListener(listener, data, mergedContext);
|
|
1767
|
-
} catch (error) {
|
|
1768
|
-
console.error("[overlays/handles] command observer failed", error);
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
if (options?.removeAfterSuccess !== false) {
|
|
1772
|
-
this.deleteEntry(callbackId, true);
|
|
1773
|
-
this.s.groups.delete(groupId);
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1776
|
-
/** Report progress to a callback (or every callback of a group) without removing it. */
|
|
1777
|
-
updateProgress(id, progress, options) {
|
|
1778
|
-
const progressInfo = { progress, status: options?.status || "running" };
|
|
1779
|
-
if (options?.error !== void 0) progressInfo.error = options.error;
|
|
1780
|
-
if (options?.groupId) {
|
|
1781
|
-
this.triggerGroup(id, null, { progress: progressInfo, removeAfterTrigger: false });
|
|
1782
|
-
} else {
|
|
1783
|
-
this.triggerWithContext(id, null, { progress: progressInfo, removeAfterTrigger: false });
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
/** Create a new, empty group and return its id. */
|
|
1787
|
-
createGroup() {
|
|
1788
|
-
const groupId = newHandleId();
|
|
1789
|
-
this.s.groups.set(groupId, /* @__PURE__ */ new Set());
|
|
1790
|
-
return groupId;
|
|
1791
|
-
}
|
|
1792
|
-
/** Remove one entry (and its group/owner membership). */
|
|
1793
|
-
remove(callbackId) {
|
|
1794
|
-
this.deleteEntry(callbackId, true);
|
|
1795
|
-
}
|
|
1796
|
-
/** Alias of `remove` — the preferred name when unregistering a handle on unmount. */
|
|
1797
|
-
unregister(callbackId) {
|
|
1798
|
-
this.remove(callbackId);
|
|
1799
|
-
}
|
|
1800
|
-
/** The stored callback or object handle for an id, without invoking it. */
|
|
1801
|
-
get(callbackId) {
|
|
1802
|
-
return this.s.callbacks.get(callbackId)?.callback;
|
|
1803
|
-
}
|
|
1804
|
-
/** True when the id is registered. */
|
|
1805
|
-
has(callbackId) {
|
|
1806
|
-
return this.s.callbacks.has(callbackId);
|
|
1807
|
-
}
|
|
1808
|
-
/**
|
|
1809
|
-
* Register an object handle (a widget handle, an editor API, …). The object occupies the slot;
|
|
1810
|
-
* it is never invoked by `trigger`, only retrieved with `get`.
|
|
1811
|
-
*/
|
|
1812
|
-
registerWidgetHandle(handle, options = {}) {
|
|
1813
|
-
return this.registerEntry(handle, options.owner === void 0 ? {} : { owner: options.owner });
|
|
1814
|
-
}
|
|
1815
|
-
/** Remove a group and all its callbacks. */
|
|
1816
|
-
removeGroup(groupId) {
|
|
1817
|
-
removeHandleGroup(groupId);
|
|
1818
|
-
}
|
|
1819
|
-
/** Remove everything registered with `owner` (an InstanceKey). Returns how many were removed. */
|
|
1820
|
-
disposeOwner(owner) {
|
|
1821
|
-
const s = this.s;
|
|
1822
|
-
const owned = s.owners.get(owner);
|
|
1823
|
-
if (!owned) return 0;
|
|
1824
|
-
s.owners.delete(owner);
|
|
1825
|
-
const ids = [...owned];
|
|
1826
|
-
for (const callbackId of ids) this.deleteEntry(callbackId, false);
|
|
1827
|
-
if (ids.length > 0) this.notifyRegistry();
|
|
1828
|
-
return ids.length;
|
|
1829
|
-
}
|
|
1830
|
-
/** Ids currently owned by `owner`. */
|
|
1831
|
-
ownedBy(owner) {
|
|
1832
|
-
return [...this.s.owners.get(owner) ?? []];
|
|
1833
|
-
}
|
|
1834
|
-
/** The member ids of a group (empty when unknown). */
|
|
1835
|
-
groupMembers(groupId) {
|
|
1836
|
-
return [...this.s.groups.get(groupId) ?? []];
|
|
1837
|
-
}
|
|
1838
|
-
/** Total registered entries (diagnostics, leak tests). */
|
|
1839
|
-
size() {
|
|
1840
|
-
return this.s.callbacks.size;
|
|
1841
|
-
}
|
|
1842
|
-
/**
|
|
1843
|
-
* The one removal path. Reads the entry BEFORE deleting it so group and owner membership shrink
|
|
1844
|
-
* (the old `removeFromGroups`-after-delete bug), then runs the entry's removal hook.
|
|
1845
|
-
*/
|
|
1846
|
-
deleteEntry(callbackId, notify) {
|
|
1847
|
-
deleteHandleEntry(callbackId, notify);
|
|
1848
|
-
}
|
|
1849
|
-
};
|
|
1850
|
-
var callbackManager = new CallbackManager();
|
|
1851
|
-
|
|
1852
|
-
// src/open/channels.ts
|
|
1853
|
-
import { globalSlot as globalSlot4 } from "@ai-matrx/kit/global-slot";
|
|
1854
|
-
var pending = () => globalSlot4("ai-matrx.summon.pendingChannels", () => /* @__PURE__ */ new Map());
|
|
1855
|
-
function dropPendingChannelsOf(owner) {
|
|
1856
|
-
const map = pending();
|
|
1857
|
-
for (const [id, entry] of [...map]) if (entry.owner === owner) map.delete(id);
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
|
-
// src/core/middleware/closeLifecycle.ts
|
|
1861
|
-
var closeState = () => globalSlot5("ai-matrx.summon.closeLifecycle", () => ({ flushers: /* @__PURE__ */ new Set() }));
|
|
1413
|
+
import { globalSlot } from "@ai-matrx/kit/global-slot";
|
|
1414
|
+
var closeState = () => globalSlot("ai-matrx.summon.closeLifecycle", () => ({ flushers: /* @__PURE__ */ new Set() }));
|
|
1862
1415
|
function registerCloseFlusher(flush) {
|
|
1863
1416
|
const { flushers } = closeState();
|
|
1864
1417
|
flushers.add(flush);
|
|
@@ -1869,8 +1422,8 @@ function registerCloseFlusher(flush) {
|
|
|
1869
1422
|
function dedupe(identities) {
|
|
1870
1423
|
return [...new Map(identities.map((identity) => [`${identity.overlayId}:${identity.instanceId}`, identity])).values()];
|
|
1871
1424
|
}
|
|
1872
|
-
function preservedIdentities(
|
|
1873
|
-
const wm =
|
|
1425
|
+
function preservedIdentities(state, overlayId) {
|
|
1426
|
+
const wm = state.windowManager;
|
|
1874
1427
|
if (!wm) return [];
|
|
1875
1428
|
const identities = [];
|
|
1876
1429
|
for (const entry of Object.values(wm.windows)) {
|
|
@@ -1884,7 +1437,7 @@ function preservedIdentities(state2, overlayId) {
|
|
|
1884
1437
|
}
|
|
1885
1438
|
return identities;
|
|
1886
1439
|
}
|
|
1887
|
-
function
|
|
1440
|
+
function isPlainRecord2(value) {
|
|
1888
1441
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1889
1442
|
}
|
|
1890
1443
|
var CLOSE_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -1909,11 +1462,11 @@ function closeInstanceResources(api, key) {
|
|
|
1909
1462
|
if (keepAlive !== "restore" && hasState) api.dispatch(clearOverlayState({ key }));
|
|
1910
1463
|
}
|
|
1911
1464
|
var closeLifecycleMiddleware = (api) => (next) => (action) => {
|
|
1912
|
-
if (!
|
|
1465
|
+
if (!isPlainRecord2(action) || typeof action.type !== "string" || !CLOSE_TYPES.has(action.type)) {
|
|
1913
1466
|
return next(action);
|
|
1914
1467
|
}
|
|
1915
1468
|
const type = action.type;
|
|
1916
|
-
const payload =
|
|
1469
|
+
const payload = isPlainRecord2(action.payload) ? action.payload : null;
|
|
1917
1470
|
const before = api.getState();
|
|
1918
1471
|
const openBefore = new Set(listOpenInstanceKeys(before));
|
|
1919
1472
|
let closing = [];
|
|
@@ -1959,12 +1512,12 @@ var closeLifecycleMiddleware = (api) => (next) => (action) => {
|
|
|
1959
1512
|
};
|
|
1960
1513
|
|
|
1961
1514
|
// src/core/middleware/renderWatchdog.ts
|
|
1962
|
-
import { globalSlot as
|
|
1515
|
+
import { globalSlot as globalSlot2 } from "@ai-matrx/kit/global-slot";
|
|
1963
1516
|
var LAZY_WINDOW_MOUNT_DEADLINE_MS = process.env.NODE_ENV === "production" ? 12e3 : 45e3;
|
|
1964
1517
|
var OPEN_TYPE = "overlays/openOverlay";
|
|
1965
1518
|
var TOGGLE_TYPE = "overlays/toggleOverlay";
|
|
1966
1519
|
var DEFAULT_INSTANCE_ID2 = "default";
|
|
1967
|
-
function
|
|
1520
|
+
function isPlainRecord3(value) {
|
|
1968
1521
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1969
1522
|
}
|
|
1970
1523
|
var CHECK_DELAY_MS = 2500;
|
|
@@ -1974,7 +1527,7 @@ var NO_MOUNT_DEADLINE_MS = LAZY_WINDOW_MOUNT_DEADLINE_MS;
|
|
|
1974
1527
|
var TOAST_DURATION_MS = 8e3;
|
|
1975
1528
|
var RECOVERY_POLL_MS = 500;
|
|
1976
1529
|
var RENDER_WATCHDOG_SLOT = "ai-matrx.summon.renderWatchdog";
|
|
1977
|
-
var watchdogState = () =>
|
|
1530
|
+
var watchdogState = () => globalSlot2(RENDER_WATCHDOG_SLOT, () => ({
|
|
1978
1531
|
renderAcks: /* @__PURE__ */ new Map(),
|
|
1979
1532
|
ackWaiters: /* @__PURE__ */ new Map(),
|
|
1980
1533
|
watches: /* @__PURE__ */ new Map()
|
|
@@ -2050,13 +1603,13 @@ function endWatch(watch) {
|
|
|
2050
1603
|
watchdogState().watches.delete(watch.overlayId);
|
|
2051
1604
|
}
|
|
2052
1605
|
function evaluate(store, watch) {
|
|
2053
|
-
const
|
|
2054
|
-
if (!selectIsOverlayOpen(
|
|
1606
|
+
const state = store.getState();
|
|
1607
|
+
if (!selectIsOverlayOpen(state, watch.overlayId, DEFAULT_INSTANCE_ID2)) {
|
|
2055
1608
|
return null;
|
|
2056
1609
|
}
|
|
2057
1610
|
const ack = watchdogState().renderAcks.get(watch.overlayId);
|
|
2058
1611
|
const windowId = ack?.kind === "window" ? ack.windowId : watch.slug;
|
|
2059
|
-
const entry =
|
|
1612
|
+
const entry = state.windowManager.windows[windowId];
|
|
2060
1613
|
const { vw, vh, degenerate } = safeViewportDims();
|
|
2061
1614
|
return {
|
|
2062
1615
|
viewportWidth: vw,
|
|
@@ -2065,14 +1618,14 @@ function evaluate(store, watch) {
|
|
|
2065
1618
|
renderAcknowledgement: ack?.kind ?? "none",
|
|
2066
1619
|
diag: diagnoseOverlayRender({
|
|
2067
1620
|
entry,
|
|
2068
|
-
windowsHidden:
|
|
1621
|
+
windowsHidden: state.windowManager.windowsHidden,
|
|
2069
1622
|
viewportWidth: vw,
|
|
2070
1623
|
viewportHeight: vh,
|
|
2071
1624
|
surfaceAcknowledged: ack?.kind === "surface"
|
|
2072
1625
|
}),
|
|
2073
1626
|
windowId,
|
|
2074
1627
|
entry,
|
|
2075
|
-
windowsHidden:
|
|
1628
|
+
windowsHidden: state.windowManager.windowsHidden
|
|
2076
1629
|
};
|
|
2077
1630
|
}
|
|
2078
1631
|
function startWatch(store, ports, overlayId, slug, label) {
|
|
@@ -2153,7 +1706,7 @@ function scream(store, watch, res) {
|
|
|
2153
1706
|
onClick: () => {
|
|
2154
1707
|
const dims = safeViewportDims();
|
|
2155
1708
|
store.dispatch(
|
|
2156
|
-
|
|
1709
|
+
revealWindow({
|
|
2157
1710
|
id: acknowledgedWindowId(overlayId, watch.slug),
|
|
2158
1711
|
viewportWidth: dims.vw,
|
|
2159
1712
|
viewportHeight: dims.vh
|
|
@@ -2191,21 +1744,21 @@ function createOverlayRenderWatchdogMiddleware(ports) {
|
|
|
2191
1744
|
const typed = action;
|
|
2192
1745
|
if (typed.type !== OPEN_TYPE && typed.type !== TOGGLE_TYPE) return result;
|
|
2193
1746
|
const payload = typed.payload;
|
|
2194
|
-
const overlayId =
|
|
1747
|
+
const overlayId = isPlainRecord3(payload) && typeof payload.overlayId === "string" ? payload.overlayId : void 0;
|
|
2195
1748
|
if (!overlayId) return result;
|
|
2196
|
-
const instanceIdRaw =
|
|
1749
|
+
const instanceIdRaw = isPlainRecord3(payload) && typeof payload.instanceId === "string" ? payload.instanceId : void 0;
|
|
2197
1750
|
const meta = getOverlayMeta(overlayId);
|
|
2198
1751
|
if (!meta || !watchdogTracksOpen(meta, instanceIdRaw ?? DEFAULT_INSTANCE_ID2)) {
|
|
2199
1752
|
return result;
|
|
2200
1753
|
}
|
|
2201
|
-
const
|
|
2202
|
-
if (!selectIsOverlayOpen(
|
|
1754
|
+
const state = store.getState();
|
|
1755
|
+
if (!selectIsOverlayOpen(state, overlayId, DEFAULT_INSTANCE_ID2)) {
|
|
2203
1756
|
return result;
|
|
2204
1757
|
}
|
|
2205
1758
|
const slug = defaultWindowIdFor(meta);
|
|
2206
1759
|
const revealDims = safeViewportDims();
|
|
2207
1760
|
store.dispatch(
|
|
2208
|
-
|
|
1761
|
+
revealWindow({
|
|
2209
1762
|
id: acknowledgedWindowId(overlayId, slug),
|
|
2210
1763
|
viewportWidth: revealDims.vw,
|
|
2211
1764
|
viewportHeight: revealDims.vh
|
|
@@ -2252,19 +1805,6 @@ function buildDockWindowPayload(windowId) {
|
|
|
2252
1805
|
};
|
|
2253
1806
|
}
|
|
2254
1807
|
|
|
2255
|
-
// src/open/gate.ts
|
|
2256
|
-
import { globalSlot as globalSlot7 } from "@ai-matrx/kit/global-slot";
|
|
2257
|
-
var slot = () => globalSlot7("ai-matrx.summon.gate", () => ({ core: null, loading: null, gates: /* @__PURE__ */ new Set(), listeners: /* @__PURE__ */ new Set() }));
|
|
2258
|
-
function installSummonCore(core) {
|
|
2259
|
-
const s = slot();
|
|
2260
|
-
if (s.core) return;
|
|
2261
|
-
s.core = core;
|
|
2262
|
-
const gates = [...s.gates];
|
|
2263
|
-
s.gates.clear();
|
|
2264
|
-
for (const gate of gates) gate.install(core);
|
|
2265
|
-
for (const listener of [...s.listeners]) listener();
|
|
2266
|
-
}
|
|
2267
|
-
|
|
2268
1808
|
// src/index.ts
|
|
2269
1809
|
var summonCore = { reducers: summonReducers, createMiddleware: createSummonMiddleware };
|
|
2270
1810
|
installSummonCore(summonCore);
|
|
@@ -2292,7 +1832,7 @@ export {
|
|
|
2292
1832
|
ackOverlaySurfaceRender,
|
|
2293
1833
|
allOverlayMeta,
|
|
2294
1834
|
anonymousIdentity,
|
|
2295
|
-
|
|
1835
|
+
arrangeActiveWindows,
|
|
2296
1836
|
buildDockWindowPayload,
|
|
2297
1837
|
centerRectInViewport,
|
|
2298
1838
|
clampAllWindowRects,
|
|
@@ -2304,7 +1844,7 @@ export {
|
|
|
2304
1844
|
clearOverlaySurfaceRender,
|
|
2305
1845
|
clearWindowPersistenceState,
|
|
2306
1846
|
closeAllInstancesOfOverlay,
|
|
2307
|
-
|
|
1847
|
+
closeAllOverlays,
|
|
2308
1848
|
closeLifecycleMiddleware,
|
|
2309
1849
|
closeOverlay,
|
|
2310
1850
|
closeOverlaysBoundToPage,
|
|
@@ -2322,7 +1862,7 @@ export {
|
|
|
2322
1862
|
diagnoseOverlayRender,
|
|
2323
1863
|
discardPendingWindowSession,
|
|
2324
1864
|
dockWindow,
|
|
2325
|
-
|
|
1865
|
+
focusWindow,
|
|
2326
1866
|
getGrid12Rect,
|
|
2327
1867
|
getGrid4Rect,
|
|
2328
1868
|
getGrid6Rect,
|
|
@@ -2347,7 +1887,7 @@ export {
|
|
|
2347
1887
|
locationRouter,
|
|
2348
1888
|
markWindowClosing,
|
|
2349
1889
|
maximizeWindow,
|
|
2350
|
-
|
|
1890
|
+
minimizeAll,
|
|
2351
1891
|
minimizeWindow,
|
|
2352
1892
|
moveTraySlot,
|
|
2353
1893
|
openOverlay,
|
|
@@ -2357,14 +1897,14 @@ export {
|
|
|
2357
1897
|
overlaysReducer,
|
|
2358
1898
|
parseInstanceKey,
|
|
2359
1899
|
popOutWindow,
|
|
2360
|
-
|
|
1900
|
+
pruneStaleInstances,
|
|
2361
1901
|
raiseTransientWindow,
|
|
2362
1902
|
recomputeTrayPositions,
|
|
2363
1903
|
rectOnScreen,
|
|
2364
1904
|
rectsEqual,
|
|
2365
1905
|
registerCloseFlusher,
|
|
2366
1906
|
registerOverlayMeta,
|
|
2367
|
-
|
|
1907
|
+
registerSyncEntry,
|
|
2368
1908
|
registerWindow,
|
|
2369
1909
|
releaseOverlayInstance,
|
|
2370
1910
|
releaseTransientWindow,
|
|
@@ -2372,10 +1912,10 @@ export {
|
|
|
2372
1912
|
resetOverlayRegistry,
|
|
2373
1913
|
resetOverlayRenderWatchdog,
|
|
2374
1914
|
resolvePorts,
|
|
2375
|
-
|
|
2376
|
-
|
|
1915
|
+
restoreAll,
|
|
1916
|
+
restoreWindow,
|
|
2377
1917
|
restoreWindowState,
|
|
2378
|
-
|
|
1918
|
+
revealWindow,
|
|
2379
1919
|
safeViewportDims,
|
|
2380
1920
|
selectActivePipWindowId,
|
|
2381
1921
|
selectAllMinimized,
|
|
@@ -2405,19 +1945,19 @@ export {
|
|
|
2405
1945
|
selectWindowZIndex,
|
|
2406
1946
|
selectWindowsHidden,
|
|
2407
1947
|
setHydrated,
|
|
2408
|
-
|
|
1948
|
+
setOverlayStateValue,
|
|
2409
1949
|
setPopoutCandidate,
|
|
2410
1950
|
subscribeToOverlayRegistry,
|
|
2411
1951
|
summonCore,
|
|
2412
1952
|
summonReducers,
|
|
2413
1953
|
toggleOverlay,
|
|
2414
|
-
|
|
1954
|
+
toggleWindowsHidden,
|
|
2415
1955
|
trayChipsPerRow,
|
|
2416
1956
|
traySlotRect,
|
|
2417
|
-
|
|
1957
|
+
unregisterSyncEntry,
|
|
2418
1958
|
unregisterWindow,
|
|
2419
1959
|
updateWindowPersistence,
|
|
2420
|
-
|
|
1960
|
+
updateWindowRect,
|
|
2421
1961
|
updateWindowTitle,
|
|
2422
1962
|
watchdogTracksOpen,
|
|
2423
1963
|
windowManagerReducer,
|