react-os-shell 4.2.2 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +5 -0
  2. package/dist/{Browser-TPAIWPZX.js → Browser-YVV3HOKJ.js} +6 -6
  3. package/dist/{Browser-TPAIWPZX.js.map → Browser-YVV3HOKJ.js.map} +1 -1
  4. package/dist/{Calculator-RCNLBRHK.js → Calculator-GBC3FLAJ.js} +5 -5
  5. package/dist/{Calculator-RCNLBRHK.js.map → Calculator-GBC3FLAJ.js.map} +1 -1
  6. package/dist/ConfirmDialog-R7NZVI2V.js +4 -0
  7. package/dist/{ConfirmDialog-QMBUHDXK.js.map → ConfirmDialog-R7NZVI2V.js.map} +1 -1
  8. package/dist/{CurrencyConverter-CM5OTXWF.js → CurrencyConverter-URPZQBNV.js} +5 -5
  9. package/dist/{CurrencyConverter-CM5OTXWF.js.map → CurrencyConverter-URPZQBNV.js.map} +1 -1
  10. package/dist/{Documents-3BPIAGQT.js → Documents-5SFFQZBP.js} +6 -6
  11. package/dist/{Documents-3BPIAGQT.js.map → Documents-5SFFQZBP.js.map} +1 -1
  12. package/dist/{Files-CR3L5C2L.js → Files-YQJRHUGF.js} +8 -8
  13. package/dist/{Files-CR3L5C2L.js.map → Files-YQJRHUGF.js.map} +1 -1
  14. package/dist/{Notepad-C6JHCCF2.js → Notepad-FUQ74K4N.js} +6 -6
  15. package/dist/{Notepad-C6JHCCF2.js.map → Notepad-FUQ74K4N.js.map} +1 -1
  16. package/dist/{PomodoroTimer-EZMBYLQX.js → PomodoroTimer-QQOMBVP3.js} +6 -6
  17. package/dist/{PomodoroTimer-EZMBYLQX.js.map → PomodoroTimer-QQOMBVP3.js.map} +1 -1
  18. package/dist/{Preview-TFDEMTSH.js → Preview-OP4IUJFT.js} +6 -6
  19. package/dist/{Preview-TFDEMTSH.js.map → Preview-OP4IUJFT.js.map} +1 -1
  20. package/dist/{Sidebar-VF2IOOFX.js → Sidebar-E553SOXC.js} +4 -4
  21. package/dist/{Sidebar-VF2IOOFX.js.map → Sidebar-E553SOXC.js.map} +1 -1
  22. package/dist/{Spreadsheet-FRUPALW4.js → Spreadsheet-GADWOYDX.js} +6 -6
  23. package/dist/{Spreadsheet-FRUPALW4.js.map → Spreadsheet-GADWOYDX.js.map} +1 -1
  24. package/dist/{Stock-HL42NPTM.js → Stock-33C4U7CR.js} +5 -5
  25. package/dist/{Stock-HL42NPTM.js.map → Stock-33C4U7CR.js.map} +1 -1
  26. package/dist/{Weather-N74AKS6V.js → Weather-G3XHTB75.js} +5 -5
  27. package/dist/{Weather-N74AKS6V.js.map → Weather-G3XHTB75.js.map} +1 -1
  28. package/dist/{WorldClock-A2EDB57H.js → WorldClock-ZUVI3LBN.js} +5 -5
  29. package/dist/{WorldClock-A2EDB57H.js.map → WorldClock-ZUVI3LBN.js.map} +1 -1
  30. package/dist/apps/index.js +18 -18
  31. package/dist/chunk-3NZSR3ZG.js +20 -0
  32. package/dist/chunk-3NZSR3ZG.js.map +1 -0
  33. package/dist/{chunk-QJXXSMPG.js → chunk-5HCDJPX7.js} +3 -3
  34. package/dist/{chunk-QJXXSMPG.js.map → chunk-5HCDJPX7.js.map} +1 -1
  35. package/dist/{chunk-6Q4KYGMH.js → chunk-DKDD5KXG.js} +14 -3
  36. package/dist/chunk-DKDD5KXG.js.map +1 -0
  37. package/dist/{chunk-SI4XHEMM.js → chunk-EF5W3EXL.js} +285 -19
  38. package/dist/chunk-EF5W3EXL.js.map +1 -0
  39. package/dist/chunk-GDOCYHAG.js +7 -0
  40. package/dist/{chunk-D36OPVAT.js.map → chunk-GDOCYHAG.js.map} +1 -1
  41. package/dist/{chunk-CWFH34LM.js → chunk-LBY7KH2W.js} +3 -3
  42. package/dist/{chunk-CWFH34LM.js.map → chunk-LBY7KH2W.js.map} +1 -1
  43. package/dist/{chunk-5TU6DT3E.js → chunk-LSFZJZTQ.js} +3 -3
  44. package/dist/{chunk-5TU6DT3E.js.map → chunk-LSFZJZTQ.js.map} +1 -1
  45. package/dist/{chunk-RKNJSV2T.js → chunk-PZTYN2RX.js} +5 -5
  46. package/dist/{chunk-RKNJSV2T.js.map → chunk-PZTYN2RX.js.map} +1 -1
  47. package/dist/{chunk-52RFL3OQ.js → chunk-QAKURGOG.js} +3 -3
  48. package/dist/{chunk-52RFL3OQ.js.map → chunk-QAKURGOG.js.map} +1 -1
  49. package/dist/index.d.ts +493 -157
  50. package/dist/index.js +255 -85
  51. package/dist/index.js.map +1 -1
  52. package/package.json +3 -2
  53. package/dist/ConfirmDialog-QMBUHDXK.js +0 -4
  54. package/dist/chunk-6Q4KYGMH.js.map +0 -1
  55. package/dist/chunk-ADJ3CERD.js +0 -31
  56. package/dist/chunk-ADJ3CERD.js.map +0 -1
  57. package/dist/chunk-D36OPVAT.js +0 -7
  58. package/dist/chunk-SI4XHEMM.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { glassStyle, GLASS_DIVIDER, navIcons } from './chunk-6Q4KYGMH.js';
2
- import { createContext, Component, useContext, useState, useRef, useEffect, useCallback, useSyncExternalStore, useLayoutEffect, isValidElement, cloneElement, Suspense } from 'react';
1
+ import { useShellAuth, glassStyle, GLASS_DIVIDER, navIcons } from './chunk-DKDD5KXG.js';
2
+ import { createContext, Component, useReducer, useRef, useCallback, useState, useEffect, useMemo, useContext, useId, useSyncExternalStore, useLayoutEffect, isValidElement, cloneElement, Suspense } from 'react';
3
3
  import { Dialog, DialogBackdrop, DialogPanel, DialogTitle } from '@headlessui/react';
4
4
  import { XMarkIcon, ExclamationTriangleIcon } from '@heroicons/react/24/outline';
5
5
  import { createPortal } from 'react-dom';
@@ -123,6 +123,217 @@ var WindowErrorBoundary = class extends Component {
123
123
  return this.props.children;
124
124
  }
125
125
  };
126
+
127
+ // src/hooks/undoHistory.ts
128
+ var UNDO_LIMIT = 100;
129
+ var emptyUndoState = { past: [], future: [] };
130
+ function undoReducer(state, action) {
131
+ switch (action.type) {
132
+ case "record": {
133
+ const newest = state.past[state.past.length - 1];
134
+ if (action.step.coalesceKey !== null && newest?.coalesceKey === action.step.coalesceKey) {
135
+ return state.future.length === 0 ? state : { ...state, future: [] };
136
+ }
137
+ const past = [...state.past, action.step];
138
+ return {
139
+ past: past.length > UNDO_LIMIT ? past.slice(past.length - UNDO_LIMIT) : past,
140
+ future: []
141
+ };
142
+ }
143
+ case "undo": {
144
+ if (state.past.length === 0) return state;
145
+ return {
146
+ past: state.past.slice(0, -1),
147
+ future: [action.redoStep, ...state.future]
148
+ };
149
+ }
150
+ case "redo": {
151
+ if (state.future.length === 0) return state;
152
+ return {
153
+ past: [...state.past, action.undoStep],
154
+ future: state.future.slice(1)
155
+ };
156
+ }
157
+ case "clear":
158
+ return state.past.length === 0 && state.future.length === 0 ? state : emptyUndoState;
159
+ }
160
+ }
161
+ var TEXT_ENTRY = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA", "SELECT"]);
162
+ function matchUndoHotkey(e) {
163
+ if (!(e.metaKey || e.ctrlKey) || e.altKey) return null;
164
+ const key = e.key.toLowerCase();
165
+ const action = key === "z" ? e.shiftKey ? "redo" : "undo" : key === "y" && e.ctrlKey && !e.metaKey && !e.shiftKey ? "redo" : null;
166
+ if (!action) return null;
167
+ const target = e.target;
168
+ if (target?.isContentEditable) return null;
169
+ if (target?.tagName && TEXT_ENTRY.has(target.tagName.toUpperCase())) return null;
170
+ return action;
171
+ }
172
+ var UndoContext = createContext(null);
173
+ var RUNAWAY_LIMIT = 500;
174
+ var RUNAWAY_QUIET_MS = 250;
175
+ function UndoProvider({ children, canEdit = true, perms, windowId }) {
176
+ const [state, dispatch] = useReducer(undoReducer, emptyUndoState);
177
+ const slices = useRef(/* @__PURE__ */ new Map());
178
+ const { hasAnyPerm } = useShellAuth();
179
+ const enabled = canEdit && (perms && perms.length > 0 ? hasAnyPerm(perms) : true);
180
+ const pending = useRef(null);
181
+ const suspended = useRef(false);
182
+ const snapshot = useCallback(() => {
183
+ const values = {};
184
+ for (const [id, slice] of slices.current) values[id] = slice.getLast();
185
+ return values;
186
+ }, []);
187
+ const register = useCallback((id, slice) => {
188
+ slices.current.set(id, slice);
189
+ }, []);
190
+ const unregister = useCallback((id) => {
191
+ slices.current.delete(id);
192
+ }, []);
193
+ const runaway = useRef({ last: 0, count: 0, tripped: false });
194
+ const record = useCallback((label, coalesceKey) => {
195
+ if (!enabled || suspended.current || pending.current) return;
196
+ const r = runaway.current;
197
+ if (r.tripped) return;
198
+ const now = Date.now();
199
+ if (now - r.last > RUNAWAY_QUIET_MS) r.count = 0;
200
+ r.last = now;
201
+ if (++r.count > RUNAWAY_LIMIT) {
202
+ r.tripped = true;
203
+ console.error(
204
+ `[react-os-shell] UndoProvider: "${label}" recorded ${RUNAWAY_LIMIT} undo steps with no pause between them, which no user action can do. The value passed to useUndoable for this slice is almost certainly rebuilt on every render (a .map/.filter/object literal in the call) rather than held in state, so it reads as changed every time \u2014 and since recording a step re-renders the form, that is a loop. Undo recording is now off for this form to keep the tab responsive.`
205
+ );
206
+ return;
207
+ }
208
+ pending.current = { values: snapshot(), label, coalesceKey };
209
+ queueMicrotask(() => {
210
+ const step = pending.current;
211
+ pending.current = null;
212
+ if (step) dispatch({ type: "record", step });
213
+ });
214
+ }, [enabled, snapshot]);
215
+ const applyValues = useCallback((values) => {
216
+ for (const [id, value2] of Object.entries(values)) {
217
+ const slice = slices.current.get(id);
218
+ if (!slice) continue;
219
+ slice.setLast(value2);
220
+ slice.apply(value2);
221
+ }
222
+ }, []);
223
+ const undo = useCallback(() => {
224
+ const step = state.past[state.past.length - 1];
225
+ if (!step) return;
226
+ const redoStep = { values: snapshot(), label: step.label, coalesceKey: null };
227
+ applyValues(step.values);
228
+ dispatch({ type: "undo", redoStep });
229
+ }, [state.past, snapshot, applyValues]);
230
+ const redo = useCallback(() => {
231
+ const step = state.future[0];
232
+ if (!step) return;
233
+ const undoStep = { values: snapshot(), label: step.label, coalesceKey: null };
234
+ applyValues(step.values);
235
+ dispatch({ type: "redo", undoStep });
236
+ }, [state.future, snapshot, applyValues]);
237
+ const [baselineToken, setBaselineToken] = useState(0);
238
+ const baseline = useCallback(() => {
239
+ suspended.current = true;
240
+ pending.current = null;
241
+ setBaselineToken((t) => t + 1);
242
+ dispatch({ type: "clear" });
243
+ }, []);
244
+ useEffect(() => {
245
+ if (!suspended.current) return;
246
+ suspended.current = false;
247
+ pending.current = null;
248
+ dispatch({ type: "clear" });
249
+ }, [baselineToken]);
250
+ const clear = baseline;
251
+ const canUndo = enabled && state.past.length > 0;
252
+ const canRedo = enabled && state.future.length > 0;
253
+ const isActive = useIsActiveWindow(windowId);
254
+ const keyed = useRef({ undo, redo, canUndo, canRedo });
255
+ keyed.current = { undo, redo, canUndo, canRedo };
256
+ useEffect(() => {
257
+ if (!isActive || !enabled) return;
258
+ const handler = (e) => {
259
+ const action = matchUndoHotkey(e);
260
+ if (!action) return;
261
+ const k = keyed.current;
262
+ if (action === "undo" ? !k.canUndo : !k.canRedo) return;
263
+ e.preventDefault();
264
+ if (action === "undo") k.undo();
265
+ else k.redo();
266
+ };
267
+ window.addEventListener("keydown", handler);
268
+ return () => window.removeEventListener("keydown", handler);
269
+ }, [isActive, enabled]);
270
+ const value = useMemo(() => ({
271
+ register,
272
+ unregister,
273
+ record,
274
+ undo,
275
+ redo,
276
+ clear,
277
+ baseline,
278
+ canUndo,
279
+ canRedo,
280
+ enabled,
281
+ undoLabel: canUndo ? state.past[state.past.length - 1].label : null,
282
+ redoLabel: canRedo ? state.future[0].label : null
283
+ }), [register, unregister, record, undo, redo, clear, baseline, canUndo, canRedo, enabled, state.past, state.future]);
284
+ return /* @__PURE__ */ jsx(UndoContext.Provider, { value, children });
285
+ }
286
+ function useUndo() {
287
+ const ctx = useContext(UndoContext);
288
+ const noop = useCallback(() => {
289
+ }, []);
290
+ return {
291
+ undo: ctx?.undo ?? noop,
292
+ redo: ctx?.redo ?? noop,
293
+ clear: ctx?.clear ?? noop,
294
+ baseline: ctx?.baseline ?? noop,
295
+ canUndo: ctx?.canUndo ?? false,
296
+ canRedo: ctx?.canRedo ?? false,
297
+ undoLabel: ctx?.undoLabel ?? null,
298
+ redoLabel: ctx?.redoLabel ?? null,
299
+ enabled: ctx?.enabled ?? false
300
+ };
301
+ }
302
+ function useUndoable(value, apply, opts) {
303
+ const ctx = useContext(UndoContext);
304
+ const id = useId();
305
+ const last = useRef(value);
306
+ const applyRef = useRef(apply);
307
+ applyRef.current = apply;
308
+ useEffect(() => {
309
+ if (!ctx) return;
310
+ ctx.register(id, {
311
+ getLast: () => last.current,
312
+ setLast: (v) => {
313
+ last.current = v;
314
+ },
315
+ apply: (v) => applyRef.current(v)
316
+ });
317
+ return () => ctx.unregister(id);
318
+ }, [ctx, id]);
319
+ const { label, coalesceKey = null } = opts;
320
+ const ctxRef = useRef(ctx);
321
+ ctxRef.current = ctx;
322
+ const optsRef = useRef({ label, coalesceKey });
323
+ optsRef.current = { label, coalesceKey };
324
+ useEffect(() => {
325
+ const c = ctxRef.current;
326
+ if (!c) return;
327
+ if (Object.is(value, last.current)) return;
328
+ c.record(optsRef.current.label, optsRef.current.coalesceKey);
329
+ last.current = value;
330
+ }, [value]);
331
+ }
332
+ function useUndoableState(initial, opts) {
333
+ const [value, setValue] = useState(initial);
334
+ useUndoable(value, (next) => setValue(() => next), opts);
335
+ return [value, setValue];
336
+ }
126
337
  function LoadingSpinner() {
127
338
  return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-8 text-sm text-gray-400", children: "Loading..." });
128
339
  }
@@ -698,13 +909,13 @@ function seedDefaultWidgetPositions(widgets) {
698
909
  }
699
910
  }
700
911
  function healWindowIds(items) {
701
- const counts = /* @__PURE__ */ new Map();
702
- for (const it of items) counts.set(it.id, (counts.get(it.id) ?? 0) + 1);
912
+ const counts2 = /* @__PURE__ */ new Map();
913
+ for (const it of items) counts2.set(it.id, (counts2.get(it.id) ?? 0) + 1);
703
914
  const seen = /* @__PURE__ */ new Set();
704
915
  const out = [];
705
916
  for (const it of items) {
706
917
  let id = it.id;
707
- if ((counts.get(it.id) ?? 0) > 1 && it.type === "modal" && it.entityType && it.entityId) {
918
+ if ((counts2.get(it.id) ?? 0) > 1 && it.type === "modal" && it.entityType && it.entityId) {
708
919
  id = `${it.entityType}:${it.entityId}`;
709
920
  }
710
921
  if (seen.has(id)) continue;
@@ -850,7 +1061,7 @@ function WindowManagerProvider({ children, windowAccentForRoute }) {
850
1061
  WindowErrorBoundary,
851
1062
  {
852
1063
  fallback: (error, reset) => /* @__PURE__ */ jsx(Modal, { open: true, onClose: () => closeEntity(item.id), title: item.label, size: "md", autoHeight: true, windowKey: item.id, children: /* @__PURE__ */ jsx(WindowCrashedFallback, { error, onReload: reset }) }),
853
- children: /* @__PURE__ */ jsx(WindowShortcutProvider, { spec: shortcutSpecFor(item), children: item.type === "page" ? /* @__PURE__ */ jsx(PageWindow, { item, onClose: () => closeEntity(item.id), accentRgb }) : /* @__PURE__ */ jsx(
1064
+ children: /* @__PURE__ */ jsx(WindowShortcutProvider, { spec: shortcutSpecFor(item), children: /* @__PURE__ */ jsx(UndoProvider, { windowId: item.id, children: item.type === "page" ? /* @__PURE__ */ jsx(PageWindow, { item, onClose: () => closeEntity(item.id), accentRgb }) : /* @__PURE__ */ jsx(
854
1065
  RestoredRegistryModal,
855
1066
  {
856
1067
  item,
@@ -859,7 +1070,7 @@ function WindowManagerProvider({ children, windowAccentForRoute }) {
859
1070
  },
860
1071
  accentRgb
861
1072
  }
862
- ) })
1073
+ ) }) })
863
1074
  },
864
1075
  item.id
865
1076
  );
@@ -1029,6 +1240,41 @@ function subscribeSwipingParentKey(cb) {
1029
1240
  subs.delete(cb);
1030
1241
  };
1031
1242
  }
1243
+
1244
+ // src/shell/perfEvents.ts
1245
+ var empty = () => ({ menus: 0, submenus: 0, menuKey: null, moveMs: 0, resizeMs: 0 });
1246
+ var collecting = false;
1247
+ var counts = empty();
1248
+ var NOOP = () => {
1249
+ };
1250
+ function setPerfCollecting(on) {
1251
+ collecting = on;
1252
+ counts = empty();
1253
+ }
1254
+ function markMenuOpen(layer, key) {
1255
+ if (!collecting) return;
1256
+ if (layer === "submenu") counts.submenus++;
1257
+ else counts.menus++;
1258
+ counts.menuKey = key;
1259
+ }
1260
+ function beginWindowGesture(kind) {
1261
+ if (!collecting) return NOOP;
1262
+ const startedAt = performance.now();
1263
+ let ended = false;
1264
+ return () => {
1265
+ if (ended) return;
1266
+ ended = true;
1267
+ if (!collecting) return;
1268
+ const elapsed = performance.now() - startedAt;
1269
+ if (kind === "move") counts.moveMs += elapsed;
1270
+ else counts.resizeMs += elapsed;
1271
+ };
1272
+ }
1273
+ function drainPerfEvents() {
1274
+ const drained = counts;
1275
+ counts = empty();
1276
+ return drained;
1277
+ }
1032
1278
  var ShellPrefsContext = createContext(null);
1033
1279
  function ShellPrefsProvider({
1034
1280
  value,
@@ -1205,7 +1451,7 @@ function CancelButton({ onClick, children, className }) {
1205
1451
  const ctx = useContext(ModalActionsContext);
1206
1452
  const handleClick = async () => {
1207
1453
  if (ctx?.isDirty) {
1208
- const { confirm: confirm2 } = await import('./ConfirmDialog-QMBUHDXK.js');
1454
+ const { confirm: confirm2 } = await import('./ConfirmDialog-R7NZVI2V.js');
1209
1455
  const ok = await confirm2({
1210
1456
  title: "Discard changes?",
1211
1457
  message: "You have unsaved changes. Are you sure you want to cancel? All changes will be lost.",
@@ -1307,6 +1553,14 @@ var windowHeightScale = {
1307
1553
  };
1308
1554
  var activationOrder = [];
1309
1555
  var activeListeners = /* @__PURE__ */ new Set();
1556
+ var _activeVersion = 0;
1557
+ function getActiveVersion() {
1558
+ return _activeVersion;
1559
+ }
1560
+ function notifyActive() {
1561
+ _activeVersion++;
1562
+ activeListeners.forEach((fn) => fn());
1563
+ }
1310
1564
  var _modalIdByKey = /* @__PURE__ */ new Map();
1311
1565
  var _keyByModalId = /* @__PURE__ */ new Map();
1312
1566
  function _insertModalIdForKey(modalId, key) {
@@ -1339,7 +1593,7 @@ function mountModal(modalId, key) {
1339
1593
  _saveOrderDebounced();
1340
1594
  }
1341
1595
  }
1342
- activeListeners.forEach((fn) => fn());
1596
+ notifyActive();
1343
1597
  window.dispatchEvent(new CustomEvent("modal-reorder"));
1344
1598
  }
1345
1599
  function activateModal(id) {
@@ -1353,7 +1607,7 @@ function activateModal(id) {
1353
1607
  _activationOrderKeys.push(key);
1354
1608
  _saveOrderDebounced();
1355
1609
  }
1356
- activeListeners.forEach((fn) => fn());
1610
+ notifyActive();
1357
1611
  window.dispatchEvent(new CustomEvent("modal-reorder"));
1358
1612
  }
1359
1613
  function _minimizeModal(modalId) {
@@ -1367,7 +1621,7 @@ function _minimizeModal(modalId) {
1367
1621
  _saveOrderDebounced();
1368
1622
  }
1369
1623
  }
1370
- activeListeners.forEach((fn) => fn());
1624
+ notifyActive();
1371
1625
  window.dispatchEvent(new CustomEvent("modal-reorder"));
1372
1626
  }
1373
1627
  var widgetIds = /* @__PURE__ */ new Set();
@@ -1380,7 +1634,7 @@ function deactivateAllModals() {
1380
1634
  return mid != null && widgetIds.has(mid);
1381
1635
  });
1382
1636
  _saveOrderDebounced();
1383
- activeListeners.forEach((fn) => fn());
1637
+ notifyActive();
1384
1638
  window.dispatchEvent(new CustomEvent("modal-reorder"));
1385
1639
  }
1386
1640
  var EDGE_THRESHOLD = 8;
@@ -1530,7 +1784,7 @@ var RESIZE_CURSOR = {
1530
1784
  w: "ew-resize"
1531
1785
  };
1532
1786
  var DRAG_THRESHOLD = 4;
1533
- function beginPointerGesture(handle, pointerId, cursor) {
1787
+ function beginPointerGesture(handle, pointerId, cursor, kind) {
1534
1788
  ensureGestureStyle();
1535
1789
  try {
1536
1790
  handle.setPointerCapture(pointerId);
@@ -1541,10 +1795,12 @@ function beginPointerGesture(handle, pointerId, cursor) {
1541
1795
  shield.setAttribute("data-drag-shield", "");
1542
1796
  shield.style.cssText = `position:fixed;inset:0;z-index:2147483647;cursor:${cursor};background:transparent;touch-action:none`;
1543
1797
  document.body.appendChild(shield);
1798
+ const endMark = beginWindowGesture(kind);
1544
1799
  let done = false;
1545
1800
  return () => {
1546
1801
  if (done) return;
1547
1802
  done = true;
1803
+ endMark();
1548
1804
  try {
1549
1805
  handle.releasePointerCapture(pointerId);
1550
1806
  } catch {
@@ -1588,6 +1844,16 @@ function useIsActiveModal(modalId) {
1588
1844
  const activeId = useSyncExternalStore(subscribeActive, getActiveModalId);
1589
1845
  return activationOrder.length <= 1 || activeId === modalId;
1590
1846
  }
1847
+ function useIsActiveWindow(windowKey) {
1848
+ useSyncExternalStore(subscribeActive, getActiveVersion);
1849
+ const ctx = useContext(ModalActionsContext);
1850
+ if (activationOrder.length <= 1) return true;
1851
+ if (windowKey) {
1852
+ const modalId = _modalIdByKey.get(windowKey);
1853
+ if (modalId != null) return getActiveModalId() === modalId;
1854
+ }
1855
+ return ctx?.active ?? getActiveModalId() != null;
1856
+ }
1591
1857
  var _exposeOn = false;
1592
1858
  var _exposeListeners = /* @__PURE__ */ new Set();
1593
1859
  function _notifyExpose() {
@@ -2038,7 +2304,7 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2038
2304
  const aidx = activationOrder.indexOf(modalId);
2039
2305
  if (aidx !== -1) {
2040
2306
  activationOrder.splice(aidx, 1);
2041
- activeListeners.forEach((fn) => fn());
2307
+ notifyActive();
2042
2308
  }
2043
2309
  const cleanupKey = _keyByModalId.get(modalId);
2044
2310
  if (cleanupKey) {
@@ -2289,7 +2555,7 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2289
2555
  const move = (ev) => {
2290
2556
  if (!endGesture) {
2291
2557
  if (Math.abs(ev.clientX - sx) < DRAG_THRESHOLD && Math.abs(ev.clientY - sy) < DRAG_THRESHOLD) return;
2292
- endGesture = beginPointerGesture(dragHandle, dragPointerId, "move");
2558
+ endGesture = beginPointerGesture(dragHandle, dragPointerId, "move", "move");
2293
2559
  if (panel) panel.style.transition = "none";
2294
2560
  }
2295
2561
  const nx = ox + ev.clientX - sx;
@@ -2399,7 +2665,7 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2399
2665
  const move = (ev) => {
2400
2666
  if (!endGesture) {
2401
2667
  if (Math.abs(ev.clientX - sx) < DRAG_THRESHOLD && Math.abs(ev.clientY - sy) < DRAG_THRESHOLD) return;
2402
- endGesture = beginPointerGesture(resizeHandle, resizePointerId, RESIZE_CURSOR[corner]);
2668
+ endGesture = beginPointerGesture(resizeHandle, resizePointerId, RESIZE_CURSOR[corner], "resize");
2403
2669
  }
2404
2670
  pending = compute(ev.clientX - sx, ev.clientY - sy);
2405
2671
  if (!raf) raf = requestAnimationFrame(flush);
@@ -3207,6 +3473,6 @@ function ConfirmProvider({ children }) {
3207
3473
  ] });
3208
3474
  }
3209
3475
 
3210
- export { CancelButton, ConfirmProvider, CopyButton, DocFavStar, LoadingSpinner, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, SIDEBAR_STRIP_W, ShellPrefsProvider, WINDOW_REGISTRY, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, client_default, commitExposeHighlight, confirm, confirmDestructive, exitExposeMode, forgetMaximizedWindowBoxes, getActiveModalId, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, isShellApiClientConfigured, prompt, registerModalEscapeInterceptor, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useConfirm, useIsMobile, useLocalStoragePrefs, useModalActive, useShellPrefs, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle };
3211
- //# sourceMappingURL=chunk-SI4XHEMM.js.map
3212
- //# sourceMappingURL=chunk-SI4XHEMM.js.map
3476
+ export { CancelButton, ConfirmProvider, CopyButton, DocFavStar, LoadingSpinner, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, SIDEBAR_STRIP_W, ShellPrefsProvider, UndoProvider, WINDOW_REGISTRY, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, beginWindowGesture, client_default, commitExposeHighlight, confirm, confirmDestructive, drainPerfEvents, exitExposeMode, forgetMaximizedWindowBoxes, getActiveModalId, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, isShellApiClientConfigured, markMenuOpen, prompt, registerModalEscapeInterceptor, setExposeHighlight, setPerfCollecting, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useConfirm, useIsActiveWindow, useIsMobile, useLocalStoragePrefs, useModalActive, useShellPrefs, useUndo, useUndoable, useUndoableState, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle };
3477
+ //# sourceMappingURL=chunk-EF5W3EXL.js.map
3478
+ //# sourceMappingURL=chunk-EF5W3EXL.js.map