@ai-matrx/summon 0.1.16 → 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 +14 -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.cjs +63 -50
- package/dist/handles.cjs.map +1 -1
- package/dist/handles.d.cts +2 -5
- package/dist/handles.d.ts +2 -5
- package/dist/handles.js +9 -259
- package/dist/handles.js.map +1 -1
- package/dist/{helpers-2NY1ha0V.d.cts → ids-83h05Ed-.d.cts} +4 -1
- package/dist/{helpers-2NY1ha0V.d.ts → ids-83h05Ed-.d.ts} +4 -1
- package/dist/index.cjs +63 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +350 -797
- 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.cjs +86 -2
- package/dist/open.cjs.map +1 -1
- package/dist/open.d.cts +22 -2
- package/dist/open.d.ts +22 -2
- package/dist/open.js +78 -359
- 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 +5 -5
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,306 +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/handles/callbackManager.ts
|
|
1583
|
-
import { globalSlot as globalSlot3 } from "@ai-matrx/kit/global-slot";
|
|
1584
|
-
|
|
1585
|
-
// src/handles/ids.ts
|
|
1586
|
-
function newHandleId() {
|
|
1587
|
-
const c = typeof globalThis.crypto === "undefined" ? void 0 : globalThis.crypto;
|
|
1588
|
-
if (c && typeof c.randomUUID === "function") return c.randomUUID();
|
|
1589
|
-
const bytes = new Uint8Array(16);
|
|
1590
|
-
if (c && typeof c.getRandomValues === "function") {
|
|
1591
|
-
c.getRandomValues(bytes);
|
|
1592
|
-
} else {
|
|
1593
|
-
for (let i = 0; i < 16; i += 1) bytes[i] = Math.floor(Math.random() * 256);
|
|
1594
|
-
}
|
|
1595
|
-
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
1596
|
-
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
1597
|
-
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
1598
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
1599
|
-
}
|
|
1600
|
-
|
|
1601
|
-
// src/handles/slot.ts
|
|
1602
|
-
var HANDLES_SLOT = "ai-matrx.summon.handles";
|
|
1603
|
-
|
|
1604
|
-
// src/handles/callbackManager.ts
|
|
1605
|
-
var handlesState = () => globalSlot3(HANDLES_SLOT, () => ({
|
|
1606
|
-
callbacks: /* @__PURE__ */ new Map(),
|
|
1607
|
-
groups: /* @__PURE__ */ new Map(),
|
|
1608
|
-
owners: /* @__PURE__ */ new Map(),
|
|
1609
|
-
registryListeners: /* @__PURE__ */ new Set()
|
|
1610
|
-
}));
|
|
1611
|
-
function invoke(slot2, data, context) {
|
|
1612
|
-
if (typeof slot2 !== "function") return void 0;
|
|
1613
|
-
return slot2(data, context);
|
|
1614
|
-
}
|
|
1615
|
-
function invokeListener(listener, data, context) {
|
|
1616
|
-
return listener(data, context);
|
|
1617
|
-
}
|
|
1618
|
-
var CallbackManager = class {
|
|
1619
|
-
get s() {
|
|
1620
|
-
return handlesState();
|
|
1621
|
-
}
|
|
1622
|
-
/**
|
|
1623
|
-
* Observe the registry itself: `listener` runs after any entry is added or removed. This lets a
|
|
1624
|
-
* view that resolves ids with `get` re-render when an id goes away (`useSyncExternalStore`).
|
|
1625
|
-
*/
|
|
1626
|
-
subscribeToRegistry(listener) {
|
|
1627
|
-
const listeners = this.s.registryListeners;
|
|
1628
|
-
listeners.add(listener);
|
|
1629
|
-
return () => {
|
|
1630
|
-
listeners.delete(listener);
|
|
1631
|
-
};
|
|
1632
|
-
}
|
|
1633
|
-
notifyRegistry() {
|
|
1634
|
-
for (const listener of [...this.s.registryListeners]) listener();
|
|
1635
|
-
}
|
|
1636
|
-
/** Register a callback; returns its id. */
|
|
1637
|
-
register(callback) {
|
|
1638
|
-
return this.registerEntry(callback, {});
|
|
1639
|
-
}
|
|
1640
|
-
/** Register with optional context, group and owner. */
|
|
1641
|
-
registerWithContext(callback, options = {}) {
|
|
1642
|
-
return this.registerEntry(callback, options);
|
|
1643
|
-
}
|
|
1644
|
-
/** @internal The one insertion path (typed helpers pass a fixed id and a removal hook). */
|
|
1645
|
-
registerEntry(slot2, options) {
|
|
1646
|
-
const s = this.s;
|
|
1647
|
-
const callbackId = options.id ?? newHandleId();
|
|
1648
|
-
if (s.callbacks.has(callbackId)) this.deleteEntry(callbackId, false);
|
|
1649
|
-
const entry = { callback: slot2 };
|
|
1650
|
-
if (options.context !== void 0) entry.context = options.context;
|
|
1651
|
-
if (options.groupId !== void 0) entry.groupId = options.groupId;
|
|
1652
|
-
if (options.owner !== void 0) entry.owner = options.owner;
|
|
1653
|
-
if (options.onRemove !== void 0) entry.onRemove = options.onRemove;
|
|
1654
|
-
s.callbacks.set(callbackId, entry);
|
|
1655
|
-
if (options.groupId !== void 0) {
|
|
1656
|
-
const group = s.groups.get(options.groupId) ?? /* @__PURE__ */ new Set();
|
|
1657
|
-
group.add(callbackId);
|
|
1658
|
-
s.groups.set(options.groupId, group);
|
|
1659
|
-
}
|
|
1660
|
-
if (options.owner !== void 0) {
|
|
1661
|
-
const owned = s.owners.get(options.owner) ?? /* @__PURE__ */ new Set();
|
|
1662
|
-
owned.add(callbackId);
|
|
1663
|
-
s.owners.set(options.owner, owned);
|
|
1664
|
-
}
|
|
1665
|
-
this.notifyRegistry();
|
|
1666
|
-
return callbackId;
|
|
1667
|
-
}
|
|
1668
|
-
/** Subscribe to results for a callback id. */
|
|
1669
|
-
subscribe(callbackId, listener) {
|
|
1670
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1671
|
-
if (!entry) return false;
|
|
1672
|
-
(entry.listeners ??= []).push(listener);
|
|
1673
|
-
return true;
|
|
1674
|
-
}
|
|
1675
|
-
/** Unsubscribe a listener from a callback id. */
|
|
1676
|
-
unsubscribe(callbackId, listener) {
|
|
1677
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1678
|
-
if (!entry || !entry.listeners) return false;
|
|
1679
|
-
const index = entry.listeners.indexOf(listener);
|
|
1680
|
-
if (index === -1) return false;
|
|
1681
|
-
entry.listeners.splice(index, 1);
|
|
1682
|
-
return true;
|
|
1683
|
-
}
|
|
1684
|
-
/** Run a callback once, notify its listeners, then remove it. */
|
|
1685
|
-
trigger(callbackId, data) {
|
|
1686
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1687
|
-
if (!entry) return;
|
|
1688
|
-
void invoke(entry.callback, data);
|
|
1689
|
-
if (entry.listeners && entry.listeners.length > 0) {
|
|
1690
|
-
for (const listener of [...entry.listeners]) void invokeListener(listener, data);
|
|
1691
|
-
}
|
|
1692
|
-
this.deleteEntry(callbackId, true);
|
|
1693
|
-
}
|
|
1694
|
-
/** Trigger with merged context and progress; removes unless `removeAfterTrigger: false`. */
|
|
1695
|
-
triggerWithContext(callbackId, data, options) {
|
|
1696
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1697
|
-
if (!entry) return;
|
|
1698
|
-
const mergedContext = {
|
|
1699
|
-
...entry.context,
|
|
1700
|
-
...options?.context,
|
|
1701
|
-
...options?.progress && { progress: options.progress }
|
|
1702
|
-
};
|
|
1703
|
-
void invoke(entry.callback, data, mergedContext);
|
|
1704
|
-
if (entry.listeners && entry.listeners.length > 0) {
|
|
1705
|
-
for (const listener of [...entry.listeners]) void invokeListener(listener, data, mergedContext);
|
|
1706
|
-
}
|
|
1707
|
-
if (options?.removeAfterTrigger !== false) this.deleteEntry(callbackId, true);
|
|
1708
|
-
}
|
|
1709
|
-
/** Trigger every callback in a group. */
|
|
1710
|
-
triggerGroup(groupId, data, options) {
|
|
1711
|
-
const group = this.s.groups.get(groupId);
|
|
1712
|
-
if (!group) return;
|
|
1713
|
-
for (const callbackId of [...group]) this.triggerWithContext(callbackId, data, options);
|
|
1714
|
-
if (options?.removeAfterTrigger !== false) this.s.groups.delete(groupId);
|
|
1715
|
-
}
|
|
1716
|
-
/**
|
|
1717
|
-
* Run the one durable command registered for a group. A command is retained on rejection so its
|
|
1718
|
-
* caller can retry, and is removed only after its promise settles successfully.
|
|
1719
|
-
*/
|
|
1720
|
-
async triggerGroupCommand(groupId, data, options) {
|
|
1721
|
-
const group = this.s.groups.get(groupId);
|
|
1722
|
-
const callbackIds = group ? [...group] : [];
|
|
1723
|
-
const callbackId = callbackIds[0];
|
|
1724
|
-
if (callbackIds.length !== 1 || callbackId === void 0) {
|
|
1725
|
-
throw new Error(`Expected exactly one command callback for group "${groupId}", found ${callbackIds.length}`);
|
|
1726
|
-
}
|
|
1727
|
-
const entry = this.s.callbacks.get(callbackId);
|
|
1728
|
-
if (!entry) throw new Error(`Command callback "${callbackId}" is no longer available`);
|
|
1729
|
-
const mergedContext = { ...entry.context, ...options?.context };
|
|
1730
|
-
await invoke(entry.callback, data, mergedContext);
|
|
1731
|
-
for (const listener of entry.listeners ?? []) {
|
|
1732
|
-
try {
|
|
1733
|
-
await invokeListener(listener, data, mergedContext);
|
|
1734
|
-
} catch (error) {
|
|
1735
|
-
console.error("[overlays/handles] command observer failed", error);
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
if (options?.removeAfterSuccess !== false) {
|
|
1739
|
-
this.deleteEntry(callbackId, true);
|
|
1740
|
-
this.s.groups.delete(groupId);
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
/** Report progress to a callback (or every callback of a group) without removing it. */
|
|
1744
|
-
updateProgress(id, progress, options) {
|
|
1745
|
-
const progressInfo = { progress, status: options?.status || "running" };
|
|
1746
|
-
if (options?.error !== void 0) progressInfo.error = options.error;
|
|
1747
|
-
if (options?.groupId) {
|
|
1748
|
-
this.triggerGroup(id, null, { progress: progressInfo, removeAfterTrigger: false });
|
|
1749
|
-
} else {
|
|
1750
|
-
this.triggerWithContext(id, null, { progress: progressInfo, removeAfterTrigger: false });
|
|
1751
|
-
}
|
|
1752
|
-
}
|
|
1753
|
-
/** Create a new, empty group and return its id. */
|
|
1754
|
-
createGroup() {
|
|
1755
|
-
const groupId = newHandleId();
|
|
1756
|
-
this.s.groups.set(groupId, /* @__PURE__ */ new Set());
|
|
1757
|
-
return groupId;
|
|
1758
|
-
}
|
|
1759
|
-
/** Remove one entry (and its group/owner membership). */
|
|
1760
|
-
remove(callbackId) {
|
|
1761
|
-
this.deleteEntry(callbackId, true);
|
|
1762
|
-
}
|
|
1763
|
-
/** Alias of `remove` — the preferred name when unregistering a handle on unmount. */
|
|
1764
|
-
unregister(callbackId) {
|
|
1765
|
-
this.remove(callbackId);
|
|
1766
|
-
}
|
|
1767
|
-
/** The stored callback or object handle for an id, without invoking it. */
|
|
1768
|
-
get(callbackId) {
|
|
1769
|
-
return this.s.callbacks.get(callbackId)?.callback;
|
|
1770
|
-
}
|
|
1771
|
-
/** True when the id is registered. */
|
|
1772
|
-
has(callbackId) {
|
|
1773
|
-
return this.s.callbacks.has(callbackId);
|
|
1774
|
-
}
|
|
1775
|
-
/**
|
|
1776
|
-
* Register an object handle (a widget handle, an editor API, …). The object occupies the slot;
|
|
1777
|
-
* it is never invoked by `trigger`, only retrieved with `get`.
|
|
1778
|
-
*/
|
|
1779
|
-
registerWidgetHandle(handle, options = {}) {
|
|
1780
|
-
return this.registerEntry(handle, options.owner === void 0 ? {} : { owner: options.owner });
|
|
1781
|
-
}
|
|
1782
|
-
/** Remove a group and all its callbacks. */
|
|
1783
|
-
removeGroup(groupId) {
|
|
1784
|
-
const s = this.s;
|
|
1785
|
-
const group = s.groups.get(groupId);
|
|
1786
|
-
if (!group) return;
|
|
1787
|
-
s.groups.delete(groupId);
|
|
1788
|
-
for (const callbackId of [...group]) this.deleteEntry(callbackId, false);
|
|
1789
|
-
this.notifyRegistry();
|
|
1790
|
-
}
|
|
1791
|
-
/** Remove everything registered with `owner` (an InstanceKey). Returns how many were removed. */
|
|
1792
|
-
disposeOwner(owner) {
|
|
1793
|
-
const s = this.s;
|
|
1794
|
-
const owned = s.owners.get(owner);
|
|
1795
|
-
if (!owned) return 0;
|
|
1796
|
-
s.owners.delete(owner);
|
|
1797
|
-
const ids = [...owned];
|
|
1798
|
-
for (const callbackId of ids) this.deleteEntry(callbackId, false);
|
|
1799
|
-
if (ids.length > 0) this.notifyRegistry();
|
|
1800
|
-
return ids.length;
|
|
1801
|
-
}
|
|
1802
|
-
/** Ids currently owned by `owner`. */
|
|
1803
|
-
ownedBy(owner) {
|
|
1804
|
-
return [...this.s.owners.get(owner) ?? []];
|
|
1805
|
-
}
|
|
1806
|
-
/** The member ids of a group (empty when unknown). */
|
|
1807
|
-
groupMembers(groupId) {
|
|
1808
|
-
return [...this.s.groups.get(groupId) ?? []];
|
|
1809
|
-
}
|
|
1810
|
-
/** Total registered entries (diagnostics, leak tests). */
|
|
1811
|
-
size() {
|
|
1812
|
-
return this.s.callbacks.size;
|
|
1813
|
-
}
|
|
1814
|
-
/**
|
|
1815
|
-
* The one removal path. Reads the entry BEFORE deleting it so group and owner membership shrink
|
|
1816
|
-
* (the old `removeFromGroups`-after-delete bug), then runs the entry's removal hook.
|
|
1817
|
-
*/
|
|
1818
|
-
deleteEntry(callbackId, notify) {
|
|
1819
|
-
const s = this.s;
|
|
1820
|
-
const entry = s.callbacks.get(callbackId);
|
|
1821
|
-
if (!entry) return;
|
|
1822
|
-
s.callbacks.delete(callbackId);
|
|
1823
|
-
if (entry.groupId !== void 0) {
|
|
1824
|
-
const group = s.groups.get(entry.groupId);
|
|
1825
|
-
group?.delete(callbackId);
|
|
1826
|
-
if (group?.size === 0) s.groups.delete(entry.groupId);
|
|
1827
|
-
}
|
|
1828
|
-
if (entry.owner !== void 0) {
|
|
1829
|
-
const owned = s.owners.get(entry.owner);
|
|
1830
|
-
owned?.delete(callbackId);
|
|
1831
|
-
if (owned?.size === 0) s.owners.delete(entry.owner);
|
|
1832
|
-
}
|
|
1833
|
-
if (notify) this.notifyRegistry();
|
|
1834
|
-
entry.onRemove?.();
|
|
1835
|
-
}
|
|
1836
|
-
};
|
|
1837
|
-
var callbackManager = new CallbackManager();
|
|
1838
|
-
|
|
1839
|
-
// src/open/channels.ts
|
|
1840
|
-
import { globalSlot as globalSlot4 } from "@ai-matrx/kit/global-slot";
|
|
1841
|
-
var pending = () => globalSlot4("ai-matrx.summon.pendingChannels", () => /* @__PURE__ */ new Map());
|
|
1842
|
-
function dropPendingChannelsOf(owner) {
|
|
1843
|
-
const map = pending();
|
|
1844
|
-
for (const [id, entry] of [...map]) if (entry.owner === owner) map.delete(id);
|
|
1845
|
-
}
|
|
1846
|
-
|
|
1847
|
-
// src/core/middleware/closeLifecycle.ts
|
|
1848
|
-
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() }));
|
|
1849
1415
|
function registerCloseFlusher(flush) {
|
|
1850
1416
|
const { flushers } = closeState();
|
|
1851
1417
|
flushers.add(flush);
|
|
@@ -1856,8 +1422,8 @@ function registerCloseFlusher(flush) {
|
|
|
1856
1422
|
function dedupe(identities) {
|
|
1857
1423
|
return [...new Map(identities.map((identity) => [`${identity.overlayId}:${identity.instanceId}`, identity])).values()];
|
|
1858
1424
|
}
|
|
1859
|
-
function preservedIdentities(
|
|
1860
|
-
const wm =
|
|
1425
|
+
function preservedIdentities(state, overlayId) {
|
|
1426
|
+
const wm = state.windowManager;
|
|
1861
1427
|
if (!wm) return [];
|
|
1862
1428
|
const identities = [];
|
|
1863
1429
|
for (const entry of Object.values(wm.windows)) {
|
|
@@ -1871,7 +1437,7 @@ function preservedIdentities(state2, overlayId) {
|
|
|
1871
1437
|
}
|
|
1872
1438
|
return identities;
|
|
1873
1439
|
}
|
|
1874
|
-
function
|
|
1440
|
+
function isPlainRecord2(value) {
|
|
1875
1441
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1876
1442
|
}
|
|
1877
1443
|
var CLOSE_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -1896,11 +1462,11 @@ function closeInstanceResources(api, key) {
|
|
|
1896
1462
|
if (keepAlive !== "restore" && hasState) api.dispatch(clearOverlayState({ key }));
|
|
1897
1463
|
}
|
|
1898
1464
|
var closeLifecycleMiddleware = (api) => (next) => (action) => {
|
|
1899
|
-
if (!
|
|
1465
|
+
if (!isPlainRecord2(action) || typeof action.type !== "string" || !CLOSE_TYPES.has(action.type)) {
|
|
1900
1466
|
return next(action);
|
|
1901
1467
|
}
|
|
1902
1468
|
const type = action.type;
|
|
1903
|
-
const payload =
|
|
1469
|
+
const payload = isPlainRecord2(action.payload) ? action.payload : null;
|
|
1904
1470
|
const before = api.getState();
|
|
1905
1471
|
const openBefore = new Set(listOpenInstanceKeys(before));
|
|
1906
1472
|
let closing = [];
|
|
@@ -1946,12 +1512,12 @@ var closeLifecycleMiddleware = (api) => (next) => (action) => {
|
|
|
1946
1512
|
};
|
|
1947
1513
|
|
|
1948
1514
|
// src/core/middleware/renderWatchdog.ts
|
|
1949
|
-
import { globalSlot as
|
|
1515
|
+
import { globalSlot as globalSlot2 } from "@ai-matrx/kit/global-slot";
|
|
1950
1516
|
var LAZY_WINDOW_MOUNT_DEADLINE_MS = process.env.NODE_ENV === "production" ? 12e3 : 45e3;
|
|
1951
1517
|
var OPEN_TYPE = "overlays/openOverlay";
|
|
1952
1518
|
var TOGGLE_TYPE = "overlays/toggleOverlay";
|
|
1953
1519
|
var DEFAULT_INSTANCE_ID2 = "default";
|
|
1954
|
-
function
|
|
1520
|
+
function isPlainRecord3(value) {
|
|
1955
1521
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1956
1522
|
}
|
|
1957
1523
|
var CHECK_DELAY_MS = 2500;
|
|
@@ -1961,7 +1527,7 @@ var NO_MOUNT_DEADLINE_MS = LAZY_WINDOW_MOUNT_DEADLINE_MS;
|
|
|
1961
1527
|
var TOAST_DURATION_MS = 8e3;
|
|
1962
1528
|
var RECOVERY_POLL_MS = 500;
|
|
1963
1529
|
var RENDER_WATCHDOG_SLOT = "ai-matrx.summon.renderWatchdog";
|
|
1964
|
-
var watchdogState = () =>
|
|
1530
|
+
var watchdogState = () => globalSlot2(RENDER_WATCHDOG_SLOT, () => ({
|
|
1965
1531
|
renderAcks: /* @__PURE__ */ new Map(),
|
|
1966
1532
|
ackWaiters: /* @__PURE__ */ new Map(),
|
|
1967
1533
|
watches: /* @__PURE__ */ new Map()
|
|
@@ -2037,13 +1603,13 @@ function endWatch(watch) {
|
|
|
2037
1603
|
watchdogState().watches.delete(watch.overlayId);
|
|
2038
1604
|
}
|
|
2039
1605
|
function evaluate(store, watch) {
|
|
2040
|
-
const
|
|
2041
|
-
if (!selectIsOverlayOpen(
|
|
1606
|
+
const state = store.getState();
|
|
1607
|
+
if (!selectIsOverlayOpen(state, watch.overlayId, DEFAULT_INSTANCE_ID2)) {
|
|
2042
1608
|
return null;
|
|
2043
1609
|
}
|
|
2044
1610
|
const ack = watchdogState().renderAcks.get(watch.overlayId);
|
|
2045
1611
|
const windowId = ack?.kind === "window" ? ack.windowId : watch.slug;
|
|
2046
|
-
const entry =
|
|
1612
|
+
const entry = state.windowManager.windows[windowId];
|
|
2047
1613
|
const { vw, vh, degenerate } = safeViewportDims();
|
|
2048
1614
|
return {
|
|
2049
1615
|
viewportWidth: vw,
|
|
@@ -2052,14 +1618,14 @@ function evaluate(store, watch) {
|
|
|
2052
1618
|
renderAcknowledgement: ack?.kind ?? "none",
|
|
2053
1619
|
diag: diagnoseOverlayRender({
|
|
2054
1620
|
entry,
|
|
2055
|
-
windowsHidden:
|
|
1621
|
+
windowsHidden: state.windowManager.windowsHidden,
|
|
2056
1622
|
viewportWidth: vw,
|
|
2057
1623
|
viewportHeight: vh,
|
|
2058
1624
|
surfaceAcknowledged: ack?.kind === "surface"
|
|
2059
1625
|
}),
|
|
2060
1626
|
windowId,
|
|
2061
1627
|
entry,
|
|
2062
|
-
windowsHidden:
|
|
1628
|
+
windowsHidden: state.windowManager.windowsHidden
|
|
2063
1629
|
};
|
|
2064
1630
|
}
|
|
2065
1631
|
function startWatch(store, ports, overlayId, slug, label) {
|
|
@@ -2140,7 +1706,7 @@ function scream(store, watch, res) {
|
|
|
2140
1706
|
onClick: () => {
|
|
2141
1707
|
const dims = safeViewportDims();
|
|
2142
1708
|
store.dispatch(
|
|
2143
|
-
|
|
1709
|
+
revealWindow({
|
|
2144
1710
|
id: acknowledgedWindowId(overlayId, watch.slug),
|
|
2145
1711
|
viewportWidth: dims.vw,
|
|
2146
1712
|
viewportHeight: dims.vh
|
|
@@ -2178,21 +1744,21 @@ function createOverlayRenderWatchdogMiddleware(ports) {
|
|
|
2178
1744
|
const typed = action;
|
|
2179
1745
|
if (typed.type !== OPEN_TYPE && typed.type !== TOGGLE_TYPE) return result;
|
|
2180
1746
|
const payload = typed.payload;
|
|
2181
|
-
const overlayId =
|
|
1747
|
+
const overlayId = isPlainRecord3(payload) && typeof payload.overlayId === "string" ? payload.overlayId : void 0;
|
|
2182
1748
|
if (!overlayId) return result;
|
|
2183
|
-
const instanceIdRaw =
|
|
1749
|
+
const instanceIdRaw = isPlainRecord3(payload) && typeof payload.instanceId === "string" ? payload.instanceId : void 0;
|
|
2184
1750
|
const meta = getOverlayMeta(overlayId);
|
|
2185
1751
|
if (!meta || !watchdogTracksOpen(meta, instanceIdRaw ?? DEFAULT_INSTANCE_ID2)) {
|
|
2186
1752
|
return result;
|
|
2187
1753
|
}
|
|
2188
|
-
const
|
|
2189
|
-
if (!selectIsOverlayOpen(
|
|
1754
|
+
const state = store.getState();
|
|
1755
|
+
if (!selectIsOverlayOpen(state, overlayId, DEFAULT_INSTANCE_ID2)) {
|
|
2190
1756
|
return result;
|
|
2191
1757
|
}
|
|
2192
1758
|
const slug = defaultWindowIdFor(meta);
|
|
2193
1759
|
const revealDims = safeViewportDims();
|
|
2194
1760
|
store.dispatch(
|
|
2195
|
-
|
|
1761
|
+
revealWindow({
|
|
2196
1762
|
id: acknowledgedWindowId(overlayId, slug),
|
|
2197
1763
|
viewportWidth: revealDims.vw,
|
|
2198
1764
|
viewportHeight: revealDims.vh
|
|
@@ -2239,19 +1805,6 @@ function buildDockWindowPayload(windowId) {
|
|
|
2239
1805
|
};
|
|
2240
1806
|
}
|
|
2241
1807
|
|
|
2242
|
-
// src/open/gate.ts
|
|
2243
|
-
import { globalSlot as globalSlot7 } from "@ai-matrx/kit/global-slot";
|
|
2244
|
-
var slot = () => globalSlot7("ai-matrx.summon.gate", () => ({ core: null, loading: null, gates: /* @__PURE__ */ new Set(), listeners: /* @__PURE__ */ new Set() }));
|
|
2245
|
-
function installSummonCore(core) {
|
|
2246
|
-
const s = slot();
|
|
2247
|
-
if (s.core) return;
|
|
2248
|
-
s.core = core;
|
|
2249
|
-
const gates = [...s.gates];
|
|
2250
|
-
s.gates.clear();
|
|
2251
|
-
for (const gate of gates) gate.install(core);
|
|
2252
|
-
for (const listener of [...s.listeners]) listener();
|
|
2253
|
-
}
|
|
2254
|
-
|
|
2255
1808
|
// src/index.ts
|
|
2256
1809
|
var summonCore = { reducers: summonReducers, createMiddleware: createSummonMiddleware };
|
|
2257
1810
|
installSummonCore(summonCore);
|
|
@@ -2279,7 +1832,7 @@ export {
|
|
|
2279
1832
|
ackOverlaySurfaceRender,
|
|
2280
1833
|
allOverlayMeta,
|
|
2281
1834
|
anonymousIdentity,
|
|
2282
|
-
|
|
1835
|
+
arrangeActiveWindows,
|
|
2283
1836
|
buildDockWindowPayload,
|
|
2284
1837
|
centerRectInViewport,
|
|
2285
1838
|
clampAllWindowRects,
|
|
@@ -2291,7 +1844,7 @@ export {
|
|
|
2291
1844
|
clearOverlaySurfaceRender,
|
|
2292
1845
|
clearWindowPersistenceState,
|
|
2293
1846
|
closeAllInstancesOfOverlay,
|
|
2294
|
-
|
|
1847
|
+
closeAllOverlays,
|
|
2295
1848
|
closeLifecycleMiddleware,
|
|
2296
1849
|
closeOverlay,
|
|
2297
1850
|
closeOverlaysBoundToPage,
|
|
@@ -2309,7 +1862,7 @@ export {
|
|
|
2309
1862
|
diagnoseOverlayRender,
|
|
2310
1863
|
discardPendingWindowSession,
|
|
2311
1864
|
dockWindow,
|
|
2312
|
-
|
|
1865
|
+
focusWindow,
|
|
2313
1866
|
getGrid12Rect,
|
|
2314
1867
|
getGrid4Rect,
|
|
2315
1868
|
getGrid6Rect,
|
|
@@ -2334,7 +1887,7 @@ export {
|
|
|
2334
1887
|
locationRouter,
|
|
2335
1888
|
markWindowClosing,
|
|
2336
1889
|
maximizeWindow,
|
|
2337
|
-
|
|
1890
|
+
minimizeAll,
|
|
2338
1891
|
minimizeWindow,
|
|
2339
1892
|
moveTraySlot,
|
|
2340
1893
|
openOverlay,
|
|
@@ -2344,14 +1897,14 @@ export {
|
|
|
2344
1897
|
overlaysReducer,
|
|
2345
1898
|
parseInstanceKey,
|
|
2346
1899
|
popOutWindow,
|
|
2347
|
-
|
|
1900
|
+
pruneStaleInstances,
|
|
2348
1901
|
raiseTransientWindow,
|
|
2349
1902
|
recomputeTrayPositions,
|
|
2350
1903
|
rectOnScreen,
|
|
2351
1904
|
rectsEqual,
|
|
2352
1905
|
registerCloseFlusher,
|
|
2353
1906
|
registerOverlayMeta,
|
|
2354
|
-
|
|
1907
|
+
registerSyncEntry,
|
|
2355
1908
|
registerWindow,
|
|
2356
1909
|
releaseOverlayInstance,
|
|
2357
1910
|
releaseTransientWindow,
|
|
@@ -2359,10 +1912,10 @@ export {
|
|
|
2359
1912
|
resetOverlayRegistry,
|
|
2360
1913
|
resetOverlayRenderWatchdog,
|
|
2361
1914
|
resolvePorts,
|
|
2362
|
-
|
|
2363
|
-
|
|
1915
|
+
restoreAll,
|
|
1916
|
+
restoreWindow,
|
|
2364
1917
|
restoreWindowState,
|
|
2365
|
-
|
|
1918
|
+
revealWindow,
|
|
2366
1919
|
safeViewportDims,
|
|
2367
1920
|
selectActivePipWindowId,
|
|
2368
1921
|
selectAllMinimized,
|
|
@@ -2392,19 +1945,19 @@ export {
|
|
|
2392
1945
|
selectWindowZIndex,
|
|
2393
1946
|
selectWindowsHidden,
|
|
2394
1947
|
setHydrated,
|
|
2395
|
-
|
|
1948
|
+
setOverlayStateValue,
|
|
2396
1949
|
setPopoutCandidate,
|
|
2397
1950
|
subscribeToOverlayRegistry,
|
|
2398
1951
|
summonCore,
|
|
2399
1952
|
summonReducers,
|
|
2400
1953
|
toggleOverlay,
|
|
2401
|
-
|
|
1954
|
+
toggleWindowsHidden,
|
|
2402
1955
|
trayChipsPerRow,
|
|
2403
1956
|
traySlotRect,
|
|
2404
|
-
|
|
1957
|
+
unregisterSyncEntry,
|
|
2405
1958
|
unregisterWindow,
|
|
2406
1959
|
updateWindowPersistence,
|
|
2407
|
-
|
|
1960
|
+
updateWindowRect,
|
|
2408
1961
|
updateWindowTitle,
|
|
2409
1962
|
watchdogTracksOpen,
|
|
2410
1963
|
windowManagerReducer,
|