@tearleads/windowing 0.1.1 → 0.2.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 (60) hide show
  1. package/README.md +32 -6
  2. package/createRequiredContext.js.map +1 -1
  3. package/index.js.map +1 -1
  4. package/menu/Menu.js.map +1 -1
  5. package/menu/MenuItem.js.map +1 -1
  6. package/menu/useContextMenuState.js.map +1 -1
  7. package/menu/useMenuKeyboard.js.map +1 -1
  8. package/package.json +1 -1
  9. package/sidebar/SidebarResize.js.map +1 -1
  10. package/window/CurrentWindowContext.js.map +1 -1
  11. package/window/Window.d.ts +8 -1
  12. package/window/Window.js +9 -12
  13. package/window/Window.js.map +1 -1
  14. package/window/WindowBody.js.map +1 -1
  15. package/window/WindowChromeActions.d.ts +7 -0
  16. package/window/WindowChromeActions.js +3 -1
  17. package/window/WindowChromeActions.js.map +1 -1
  18. package/window/WindowCloseButton.js.map +1 -1
  19. package/window/WindowMaximizeButton.js.map +1 -1
  20. package/window/WindowMenuBar.js.map +1 -1
  21. package/window/WindowMenuContext.js.map +1 -1
  22. package/window/WindowMinimizeButton.js.map +1 -1
  23. package/window/WindowResizeHandle.css +121 -32
  24. package/window/WindowResizeHandle.d.ts +8 -4
  25. package/window/WindowResizeHandle.js +18 -3
  26. package/window/WindowResizeHandle.js.map +1 -1
  27. package/window/WindowSidebar.js.map +1 -1
  28. package/window/WindowSidebarContext.js.map +1 -1
  29. package/window/WindowStateProvider/WindowStateProvider.js.map +1 -1
  30. package/window/WindowStateProvider/context.js.map +1 -1
  31. package/window/WindowStateProvider/index.js.map +1 -1
  32. package/window/WindowStateProvider/types.js.map +1 -1
  33. package/window/WindowStateProvider/useWindowActions.js.map +1 -1
  34. package/window/WindowStateProvider/useWindowStateActions.js.map +1 -1
  35. package/window/WindowStateProvider/useWindowStateData.js.map +1 -1
  36. package/window/WindowStateProvider/util/bringWindowToFront.js.map +1 -1
  37. package/window/WindowStateProvider/util/createWindowEntry.js.map +1 -1
  38. package/window/WindowStateProvider/util/findAdjacentWindow.js.map +1 -1
  39. package/window/WindowStateProvider/util/findTopWindow.js.map +1 -1
  40. package/window/WindowStateProvider/util/getMaxWindowZIndex.js.map +1 -1
  41. package/window/WindowStateProvider/util/index.js.map +1 -1
  42. package/window/WindowStateProvider/util/swapWindowZIndexes.js.map +1 -1
  43. package/window/WindowStateProvider/util/updateWindowFlag.js.map +1 -1
  44. package/window/WindowStatusBar.js.map +1 -1
  45. package/window/WindowTitleBar.d.ts +1 -0
  46. package/window/WindowTitleBar.js.map +1 -1
  47. package/window/WindowToolBar.css +6 -0
  48. package/window/WindowToolBar.js.map +1 -1
  49. package/window/useWindowGeometry.d.ts +2 -2
  50. package/window/useWindowGeometry.js +5 -5
  51. package/window/useWindowGeometry.js.map +1 -1
  52. package/window/useWindowItemRegistration.js.map +1 -1
  53. package/window/useWindowItemRegistry.js.map +1 -1
  54. package/window/useWindowKeyboardGeometry.js.map +1 -1
  55. package/window/useWindowLayout.js.map +1 -1
  56. package/window/useWindowToolbarReservationRegistry.js.map +1 -1
  57. package/window/windowGeometry.d.ts +2 -2
  58. package/window/windowGeometry.js +8 -4
  59. package/window/windowGeometry.js.map +1 -1
  60. package/window/windowMenuRegistrations.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"bringWindowToFront.js","sourceRoot":"","sources":["../../../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowStateProvider/util/bringWindowToFront.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,UAAU,kBAAkB,CAAC,OAAsB,EAAE,EAAU;IACnE,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;QACjC,IAAI,WAAW,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;YACjC,OAAO,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC/C,CAAC;QACD,IAAI,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YACvC,OAAO,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { WindowEntry } from \"../types\";\nimport { getMaxWindowZIndex } from \"./getMaxWindowZIndex\";\n\nexport function bringWindowToFront(windows: WindowEntry[], id: string) {\n const target = windows.find((windowEntry) => windowEntry.id === id);\n if (!target) {\n return windows;\n }\n\n const topZIndex = getMaxWindowZIndex(windows);\n if (target.zIndex === topZIndex) {\n return windows;\n }\n\n return windows.map((windowEntry) => {\n if (windowEntry.id === target.id) {\n return { ...windowEntry, zIndex: topZIndex };\n }\n if (windowEntry.zIndex > target.zIndex) {\n return { ...windowEntry, zIndex: windowEntry.zIndex - 1 };\n }\n return windowEntry;\n });\n}\n"]}
1
+ {"version":3,"file":"bringWindowToFront.js","sourceRoot":"","sources":["../../../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowStateProvider/util/bringWindowToFront.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,UAAU,kBAAkB,CAAC,OAAsB,EAAE,EAAU;IACnE,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;QACjC,IAAI,WAAW,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;YACjC,OAAO,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC/C,CAAC;QACD,IAAI,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YACvC,OAAO,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { WindowEntry } from \"../types\";\nimport { getMaxWindowZIndex } from \"./getMaxWindowZIndex\";\n\nexport function bringWindowToFront(windows: WindowEntry[], id: string) {\n const target = windows.find((windowEntry) => windowEntry.id === id);\n if (!target) {\n return windows;\n }\n\n const topZIndex = getMaxWindowZIndex(windows);\n if (target.zIndex === topZIndex) {\n return windows;\n }\n\n return windows.map((windowEntry) => {\n if (windowEntry.id === target.id) {\n return { ...windowEntry, zIndex: topZIndex };\n }\n if (windowEntry.zIndex > target.zIndex) {\n return { ...windowEntry, zIndex: windowEntry.zIndex - 1 };\n }\n return windowEntry;\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"createWindowEntry.js","sourceRoot":"","sources":["../../../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowStateProvider/util/createWindowEntry.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,iBAAiB,CAC/B,EAAU,EACV,KAAa,EACb,CAAS,EACT,CAAS,EACT,MAAc,EACd,SAAyB,EACzB,UAA+B,EAAE;IAEjC,OAAO;QACL,EAAE;QACF,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;QAC9C,GAAG,CAAC,OAAO,CAAC,YAAY;YACtB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,EAAE;YAC7C,CAAC,CAAC,EAAE,CAAC;QACP,KAAK;QACL,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,CAAC;QACX,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,KAAK;QAChB,MAAM;QACN,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC","sourcesContent":["import type { ComponentType } from \"react\";\nimport type { WindowCreateOptions, WindowEntry } from \"../types\";\n\nexport function createWindowEntry(\n id: string,\n title: string,\n x: number,\n y: number,\n zIndex: number,\n component?: ComponentType,\n options: WindowCreateOptions = {},\n): WindowEntry {\n return {\n id,\n ...(options.appId ? { appId: options.appId } : {}),\n initialShowSidebar: options.initialShowSidebar,\n ...(options.pathSegments\n ? { pathSegments: [...options.pathSegments] }\n : {}),\n title,\n initialX: x,\n initialY: y,\n ...(options.position ? { position: { ...options.position } } : {}),\n ...(options.size ? { size: { ...options.size } } : {}),\n maximized: false,\n minimized: false,\n zIndex,\n ...(component ? { component } : {}),\n };\n}\n"]}
1
+ {"version":3,"file":"createWindowEntry.js","sourceRoot":"","sources":["../../../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowStateProvider/util/createWindowEntry.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,iBAAiB,CAC/B,EAAU,EACV,KAAa,EACb,CAAS,EACT,CAAS,EACT,MAAc,EACd,SAAyB,EACzB,UAA+B,EAAE;IAEjC,OAAO;QACL,EAAE;QACF,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;QAC9C,GAAG,CAAC,OAAO,CAAC,YAAY;YACtB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,EAAE;YAC7C,CAAC,CAAC,EAAE,CAAC;QACP,KAAK;QACL,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,CAAC;QACX,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,KAAK;QAChB,MAAM;QACN,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC","sourcesContent":["import type { ComponentType } from \"react\";\nimport type { WindowCreateOptions, WindowEntry } from \"../types\";\n\nexport function createWindowEntry(\n id: string,\n title: string,\n x: number,\n y: number,\n zIndex: number,\n component?: ComponentType,\n options: WindowCreateOptions = {},\n): WindowEntry {\n return {\n id,\n ...(options.appId ? { appId: options.appId } : {}),\n initialShowSidebar: options.initialShowSidebar,\n ...(options.pathSegments\n ? { pathSegments: [...options.pathSegments] }\n : {}),\n title,\n initialX: x,\n initialY: y,\n ...(options.position ? { position: { ...options.position } } : {}),\n ...(options.size ? { size: { ...options.size } } : {}),\n maximized: false,\n minimized: false,\n zIndex,\n ...(component ? { component } : {}),\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"findAdjacentWindow.js","sourceRoot":"","sources":["../../../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowStateProvider/util/findAdjacentWindow.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAChC,OAAsB,EACtB,MAAmB,EACnB,SAA8B;IAE9B,IAAI,SAAS,GAAuB,IAAI,CAAC;IAEzC,KAAK,MAAM,WAAW,IAAI,OAAO,EAAE,CAAC;QAClC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,WAAW,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBACxC,SAAS;YACX,CAAC;YACD,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;gBACxD,SAAS,GAAG,WAAW,CAAC;YAC1B,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,WAAW,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QACD,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;YACxD,SAAS,GAAG,WAAW,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import type { WindowEntry, WindowMoveDirection } from \"../types\";\n\nexport function findAdjacentWindow(\n windows: WindowEntry[],\n target: WindowEntry,\n direction: WindowMoveDirection,\n) {\n let candidate: WindowEntry | null = null;\n\n for (const windowEntry of windows) {\n if (direction === \"forward\") {\n if (windowEntry.zIndex <= target.zIndex) {\n continue;\n }\n if (!candidate || windowEntry.zIndex < candidate.zIndex) {\n candidate = windowEntry;\n }\n continue;\n }\n\n if (windowEntry.zIndex >= target.zIndex) {\n continue;\n }\n if (!candidate || windowEntry.zIndex > candidate.zIndex) {\n candidate = windowEntry;\n }\n }\n\n return candidate;\n}\n"]}
1
+ {"version":3,"file":"findAdjacentWindow.js","sourceRoot":"","sources":["../../../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowStateProvider/util/findAdjacentWindow.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAChC,OAAsB,EACtB,MAAmB,EACnB,SAA8B;IAE9B,IAAI,SAAS,GAAuB,IAAI,CAAC;IAEzC,KAAK,MAAM,WAAW,IAAI,OAAO,EAAE,CAAC;QAClC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,WAAW,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBACxC,SAAS;YACX,CAAC;YACD,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;gBACxD,SAAS,GAAG,WAAW,CAAC;YAC1B,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,WAAW,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QACD,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;YACxD,SAAS,GAAG,WAAW,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import type { WindowEntry, WindowMoveDirection } from \"../types\";\n\nexport function findAdjacentWindow(\n windows: WindowEntry[],\n target: WindowEntry,\n direction: WindowMoveDirection,\n) {\n let candidate: WindowEntry | null = null;\n\n for (const windowEntry of windows) {\n if (direction === \"forward\") {\n if (windowEntry.zIndex <= target.zIndex) {\n continue;\n }\n if (!candidate || windowEntry.zIndex < candidate.zIndex) {\n candidate = windowEntry;\n }\n continue;\n }\n\n if (windowEntry.zIndex >= target.zIndex) {\n continue;\n }\n if (!candidate || windowEntry.zIndex > candidate.zIndex) {\n candidate = windowEntry;\n }\n }\n\n return candidate;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"findTopWindow.js","sourceRoot":"","sources":["../../../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowStateProvider/util/findTopWindow.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAC3B,OAAmC,EACnC,OAA8C;IAE9C,OAAO,OAAO,CAAC,MAAM,CACnB,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CACjB,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,SAAS,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAC3D,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,GAAG,EACT,IAAI,CACL,CAAC;AACJ,CAAC","sourcesContent":["import type { WindowEntry } from \"../types\";\n\n/** The highest-zIndex window matching `matches`, or null when none do. */\nexport function findTopWindow(\n windows: ReadonlyArray<WindowEntry>,\n matches: (windowEntry: WindowEntry) => boolean,\n): WindowEntry | null {\n return windows.reduce<WindowEntry | null>(\n (top, candidate) =>\n matches(candidate) && (!top || candidate.zIndex > top.zIndex)\n ? candidate\n : top,\n null,\n );\n}\n"]}
1
+ {"version":3,"file":"findTopWindow.js","sourceRoot":"","sources":["../../../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowStateProvider/util/findTopWindow.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAC3B,OAAmC,EACnC,OAA8C;IAE9C,OAAO,OAAO,CAAC,MAAM,CACnB,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CACjB,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,SAAS,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAC3D,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,GAAG,EACT,IAAI,CACL,CAAC;AACJ,CAAC","sourcesContent":["import type { WindowEntry } from \"../types\";\n\n/** The highest-zIndex window matching `matches`, or null when none do. */\nexport function findTopWindow(\n windows: ReadonlyArray<WindowEntry>,\n matches: (windowEntry: WindowEntry) => boolean,\n): WindowEntry | null {\n return windows.reduce<WindowEntry | null>(\n (top, candidate) =>\n matches(candidate) && (!top || candidate.zIndex > top.zIndex)\n ? candidate\n : top,\n null,\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"getMaxWindowZIndex.js","sourceRoot":"","sources":["../../../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowStateProvider/util/getMaxWindowZIndex.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAAC,OAAmC;IACpE,OAAO,OAAO,CAAC,MAAM,CACnB,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EACnE,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { WindowEntry } from \"../types\";\n\nexport function getMaxWindowZIndex(windows: ReadonlyArray<WindowEntry>) {\n return windows.reduce(\n (maxZIndex, windowEntry) => Math.max(maxZIndex, windowEntry.zIndex),\n 0,\n );\n}\n"]}
1
+ {"version":3,"file":"getMaxWindowZIndex.js","sourceRoot":"","sources":["../../../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowStateProvider/util/getMaxWindowZIndex.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAAC,OAAmC;IACpE,OAAO,OAAO,CAAC,MAAM,CACnB,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EACnE,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { WindowEntry } from \"../types\";\n\nexport function getMaxWindowZIndex(windows: ReadonlyArray<WindowEntry>) {\n return windows.reduce(\n (maxZIndex, windowEntry) => Math.max(maxZIndex, windowEntry.zIndex),\n 0,\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowStateProvider/util/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC","sourcesContent":["export { bringWindowToFront } from \"./bringWindowToFront\";\nexport { createWindowEntry } from \"./createWindowEntry\";\nexport { findTopWindow } from \"./findTopWindow\";\nexport { getMaxWindowZIndex } from \"./getMaxWindowZIndex\";\nexport { swapWindowZIndexes } from \"./swapWindowZIndexes\";\nexport { updateWindowFlag } from \"./updateWindowFlag\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowStateProvider/util/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC","sourcesContent":["export { bringWindowToFront } from \"./bringWindowToFront\";\nexport { createWindowEntry } from \"./createWindowEntry\";\nexport { findTopWindow } from \"./findTopWindow\";\nexport { getMaxWindowZIndex } from \"./getMaxWindowZIndex\";\nexport { swapWindowZIndexes } from \"./swapWindowZIndexes\";\nexport { updateWindowFlag } from \"./updateWindowFlag\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"swapWindowZIndexes.js","sourceRoot":"","sources":["../../../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowStateProvider/util/swapWindowZIndexes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,UAAU,kBAAkB,CAChC,OAAsB,EACtB,EAAU,EACV,SAA8B;IAE9B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAChE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;QACjC,IAAI,WAAW,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;YACjC,OAAO,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrD,CAAC;QACD,IAAI,WAAW,CAAC,EAAE,KAAK,QAAQ,CAAC,EAAE,EAAE,CAAC;YACnC,OAAO,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QACnD,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { WindowEntry, WindowMoveDirection } from \"../types\";\nimport { findAdjacentWindow } from \"./findAdjacentWindow\";\n\nexport function swapWindowZIndexes(\n windows: WindowEntry[],\n id: string,\n direction: WindowMoveDirection,\n) {\n const target = windows.find((windowEntry) => windowEntry.id === id);\n if (!target) {\n return windows;\n }\n\n const swapWith = findAdjacentWindow(windows, target, direction);\n if (!swapWith) {\n return windows;\n }\n\n return windows.map((windowEntry) => {\n if (windowEntry.id === target.id) {\n return { ...windowEntry, zIndex: swapWith.zIndex };\n }\n if (windowEntry.id === swapWith.id) {\n return { ...windowEntry, zIndex: target.zIndex };\n }\n return windowEntry;\n });\n}\n"]}
1
+ {"version":3,"file":"swapWindowZIndexes.js","sourceRoot":"","sources":["../../../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowStateProvider/util/swapWindowZIndexes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,UAAU,kBAAkB,CAChC,OAAsB,EACtB,EAAU,EACV,SAA8B;IAE9B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAChE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;QACjC,IAAI,WAAW,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;YACjC,OAAO,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrD,CAAC;QACD,IAAI,WAAW,CAAC,EAAE,KAAK,QAAQ,CAAC,EAAE,EAAE,CAAC;YACnC,OAAO,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QACnD,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { WindowEntry, WindowMoveDirection } from \"../types\";\nimport { findAdjacentWindow } from \"./findAdjacentWindow\";\n\nexport function swapWindowZIndexes(\n windows: WindowEntry[],\n id: string,\n direction: WindowMoveDirection,\n) {\n const target = windows.find((windowEntry) => windowEntry.id === id);\n if (!target) {\n return windows;\n }\n\n const swapWith = findAdjacentWindow(windows, target, direction);\n if (!swapWith) {\n return windows;\n }\n\n return windows.map((windowEntry) => {\n if (windowEntry.id === target.id) {\n return { ...windowEntry, zIndex: swapWith.zIndex };\n }\n if (windowEntry.id === swapWith.id) {\n return { ...windowEntry, zIndex: target.zIndex };\n }\n return windowEntry;\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"updateWindowFlag.js","sourceRoot":"","sources":["../../../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowStateProvider/util/updateWindowFlag.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAC9B,OAAsB,EACtB,EAAU,EACV,KAEC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CACjC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CACnE,CAAC;AACJ,CAAC","sourcesContent":["import type { WindowEntry } from \"../types\";\n\nexport function updateWindowFlag(\n windows: WindowEntry[],\n id: string,\n patch: Partial<\n Pick<WindowEntry, \"maximized\" | \"minimized\" | \"position\" | \"size\" | \"title\">\n >,\n) {\n return windows.map((windowEntry) =>\n windowEntry.id === id ? { ...windowEntry, ...patch } : windowEntry,\n );\n}\n"]}
1
+ {"version":3,"file":"updateWindowFlag.js","sourceRoot":"","sources":["../../../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowStateProvider/util/updateWindowFlag.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAC9B,OAAsB,EACtB,EAAU,EACV,KAEC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CACjC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CACnE,CAAC;AACJ,CAAC","sourcesContent":["import type { WindowEntry } from \"../types\";\n\nexport function updateWindowFlag(\n windows: WindowEntry[],\n id: string,\n patch: Partial<\n Pick<WindowEntry, \"maximized\" | \"minimized\" | \"position\" | \"size\" | \"title\">\n >,\n) {\n return windows.map((windowEntry) =>\n windowEntry.id === id ? { ...windowEntry, ...patch } : windowEntry,\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"WindowStatusBar.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowStatusBar.tsx"],"names":[],"mappings":";AAAA,OAAO,uBAAuB,CAAC;AAE/B,MAAM,UAAU,eAAe,CAAC,EAC9B,IAAI,EACJ,OAAO,GAAG,IAAI,GAIf;IACC;;;;;;;;;;;OAWG;IACH,OAAO,CACL,cAAK,SAAS,EAAC,uBAAuB,eAAW,QAAQ,EAAC,IAAI,EAAC,QAAQ,YACpE,IAAI,CAAC,CAAC,CAAC,CACN,cACE,SAAS,EACP,OAAO;gBACL,CAAC,CAAC,kBAAkB;gBACpB,CAAC,CAAC,2CAA2C,YAGhD,IAAI,GACD,CACP,CAAC,CAAC,CAAC,IAAI,GACJ,CACP,CAAC;AACJ,CAAC","sourcesContent":["import \"./WindowStatusBar.css\";\n\nexport function WindowStatusBar({\n text,\n visible = true,\n}: {\n text?: string;\n visible?: boolean;\n}) {\n /*\n * The live region stays mounted while the visible bar collapses. A `role=\"status\"`\n * region only announces when text changes on an element already in the DOM, so\n * mounting the region together with its first message loses the announcement.\n * The visible bar is skipped when empty because an empty one would hold\n * `--window-bar-height` of `--color-muted` directly above the equally-muted\n * taskbar, reading as a dead grey band rather than window chrome.\n *\n * Hiding the status bar hides only the visible band: the region stays mounted\n * and the message stays in it, visually hidden, so announcements such as the\n * keyboard move and resize instructions still reach assistive technology.\n */\n return (\n <div className=\"window-statusbar-live\" aria-live=\"polite\" role=\"status\">\n {text ? (\n <div\n className={\n visible\n ? \"window-statusbar\"\n : \"window-statusbar window-statusbar--hidden\"\n }\n >\n {text}\n </div>\n ) : null}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"WindowStatusBar.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowStatusBar.tsx"],"names":[],"mappings":";AAAA,OAAO,uBAAuB,CAAC;AAE/B,MAAM,UAAU,eAAe,CAAC,EAC9B,IAAI,EACJ,OAAO,GAAG,IAAI,GAIf;IACC;;;;;;;;;;;OAWG;IACH,OAAO,CACL,cAAK,SAAS,EAAC,uBAAuB,eAAW,QAAQ,EAAC,IAAI,EAAC,QAAQ,YACpE,IAAI,CAAC,CAAC,CAAC,CACN,cACE,SAAS,EACP,OAAO;gBACL,CAAC,CAAC,kBAAkB;gBACpB,CAAC,CAAC,2CAA2C,YAGhD,IAAI,GACD,CACP,CAAC,CAAC,CAAC,IAAI,GACJ,CACP,CAAC;AACJ,CAAC","sourcesContent":["import \"./WindowStatusBar.css\";\n\nexport function WindowStatusBar({\n text,\n visible = true,\n}: {\n text?: string;\n visible?: boolean;\n}) {\n /*\n * The live region stays mounted while the visible bar collapses. A `role=\"status\"`\n * region only announces when text changes on an element already in the DOM, so\n * mounting the region together with its first message loses the announcement.\n * The visible bar is skipped when empty because an empty one would hold\n * `--window-bar-height` of `--color-muted` directly above the equally-muted\n * taskbar, reading as a dead grey band rather than window chrome.\n *\n * Hiding the status bar hides only the visible band: the region stays mounted\n * and the message stays in it, visually hidden, so announcements such as the\n * keyboard move and resize instructions still reach assistive technology.\n */\n return (\n <div className=\"window-statusbar-live\" aria-live=\"polite\" role=\"status\">\n {text ? (\n <div\n className={\n visible\n ? \"window-statusbar\"\n : \"window-statusbar window-statusbar--hidden\"\n }\n >\n {text}\n </div>\n ) : null}\n </div>\n );\n}\n"]}
@@ -5,6 +5,7 @@ export interface WindowTitleBarAction {
5
5
  id: string;
6
6
  label: string;
7
7
  onClick: () => void;
8
+ pressed?: boolean;
8
9
  }
9
10
  export declare function WindowTitleBar({ title, titleId, onPointerDown, onMinimize, onMaximize, onClose, onMoveForward, onMoveBackward, }: {
10
11
  title: string;
@@ -1 +1 @@
1
- {"version":3,"file":"WindowTitleBar.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowTitleBar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AACrE,OAAO,EAAkB,WAAW,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAU9D,MAAM,UAAU,cAAc,CAAC,EAC7B,KAAK,EACL,OAAO,EACP,aAAa,EACb,UAAU,EACV,UAAU,EACV,OAAO,EACP,aAAa,EACb,cAAc,GAUf;IACC,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,iBAAiB,EAAE,GACxD,2BAA2B,EAAE,CAAC;IAEhC,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,CAAqC,EAAE,EAAE;QACxC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACxB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC3B,mEAAmE;QACnE,oEAAoE;QACpE,IAAI,MAAM,YAAY,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YAAE,OAAO;QAClE,aAAa,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC,EACD,CAAC,aAAa,CAAC,CAChB,CAAC;IAEF,OAAO,CACL,eACE,IAAI,EAAC,SAAS,gBACH,iBAAiB,EAC5B,SAAS,EAAC,iBAAiB,EAC3B,aAAa,EAAE,iBAAiB,EAChC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;YACvB,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,KAAK,CAAC,eAAe,EAAE,CAAC;YACxB,iBAAiB,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC,aAED,eAAM,SAAS,EAAC,uBAAuB,EAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,YAC9D,KAAK,GACD,EACP,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,oBAAoB,IAAC,OAAO,EAAE,UAAU,GAAI,EAC7C,KAAC,oBAAoB,IAAC,OAAO,EAAE,UAAU,GAAI,EAC7C,KAAC,iBAAiB,IAAC,KAAK,EAAC,cAAc,EAAC,OAAO,EAAE,OAAO,GAAI,IACxD,EACL,WAAW,IAAI,CACd,MAAC,IAAI,IACH,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,gBAAgB,EACzB,SAAS,EAAC,MAAM,aAEhB,KAAC,QAAQ,IACP,IAAI,EAAE,WAAW,EACjB,KAAK,EAAC,cAAc,EACpB,OAAO,EAAE,GAAG,EAAE;4BACZ,aAAa,EAAE,CAAC;4BAChB,gBAAgB,EAAE,CAAC;wBACrB,CAAC,GACD,EACF,KAAC,QAAQ,IACP,IAAI,EAAE,aAAa,EACnB,KAAK,EAAC,eAAe,EACrB,OAAO,EAAE,GAAG,EAAE;4BACZ,cAAc,EAAE,CAAC;4BACjB,gBAAgB,EAAE,CAAC;wBACrB,CAAC,GACD,IACG,CACR,IACG,CACP,CAAC;AACJ,CAAC","sourcesContent":["import { ArrowDownIcon } from \"@phosphor-icons/react/dist/csr/ArrowDown\";\nimport { ArrowUpIcon } from \"@phosphor-icons/react/dist/csr/ArrowUp\";\nimport { type ReactNode, useCallback } from \"react\";\nimport { Menu } from \"../menu/Menu\";\nimport { MenuItem } from \"../menu/MenuItem\";\nimport { useContextMenuPositionState } from \"../menu/useContextMenuState\";\nimport \"./WindowTitleBar.css\";\nimport { WindowCloseButton } from \"./WindowCloseButton\";\nimport { WindowMaximizeButton } from \"./WindowMaximizeButton\";\nimport { WindowMinimizeButton } from \"./WindowMinimizeButton\";\n\nexport interface WindowTitleBarAction {\n disabled?: boolean;\n icon: ReactNode;\n id: string;\n label: string;\n onClick: () => void;\n}\n\nexport function WindowTitleBar({\n title,\n titleId,\n onPointerDown,\n onMinimize,\n onMaximize,\n onClose,\n onMoveForward,\n onMoveBackward,\n}: {\n title: string;\n titleId?: string | undefined;\n onPointerDown: (e: React.PointerEvent) => void;\n onMinimize: () => void;\n onMaximize: () => void;\n onClose: () => void;\n onMoveForward: () => void;\n onMoveBackward: () => void;\n}) {\n const { closeContextMenu, contextMenu, openContextMenuAt } =\n useContextMenuPositionState();\n\n const handlePointerDown = useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n const target = e.target;\n if (e.button !== 0) return;\n // Element, not HTMLElement: an icon inside a button (including the\n // portaled context menu, whose events bubble through React) is SVG.\n if (target instanceof Element && target.closest(\"button\")) return;\n onPointerDown(e);\n },\n [onPointerDown],\n );\n\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Window controls\"\n className=\"window-titlebar\"\n onPointerDown={handlePointerDown}\n onContextMenu={(event) => {\n event.preventDefault();\n event.stopPropagation();\n openContextMenuAt({ x: event.clientX, y: event.clientY });\n }}\n >\n <span className=\"window-titlebar-title\" id={titleId} title={title}>\n {title}\n </span>\n <div className=\"window-titlebar-buttons\">\n <WindowMinimizeButton onClick={onMinimize} />\n <WindowMaximizeButton onClick={onMaximize} />\n <WindowCloseButton label=\"Close window\" onClick={onClose} />\n </div>\n {contextMenu && (\n <Menu\n position={contextMenu}\n onClose={closeContextMenu}\n direction=\"down\"\n >\n <MenuItem\n icon={ArrowUpIcon}\n label=\"Move Forward\"\n onClick={() => {\n onMoveForward();\n closeContextMenu();\n }}\n />\n <MenuItem\n icon={ArrowDownIcon}\n label=\"Move Backward\"\n onClick={() => {\n onMoveBackward();\n closeContextMenu();\n }}\n />\n </Menu>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"WindowTitleBar.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowTitleBar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AACrE,OAAO,EAAkB,WAAW,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAW9D,MAAM,UAAU,cAAc,CAAC,EAC7B,KAAK,EACL,OAAO,EACP,aAAa,EACb,UAAU,EACV,UAAU,EACV,OAAO,EACP,aAAa,EACb,cAAc,GAUf;IACC,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,iBAAiB,EAAE,GACxD,2BAA2B,EAAE,CAAC;IAEhC,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,CAAqC,EAAE,EAAE;QACxC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACxB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC3B,mEAAmE;QACnE,oEAAoE;QACpE,IAAI,MAAM,YAAY,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YAAE,OAAO;QAClE,aAAa,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC,EACD,CAAC,aAAa,CAAC,CAChB,CAAC;IAEF,OAAO,CACL,eACE,IAAI,EAAC,SAAS,gBACH,iBAAiB,EAC5B,SAAS,EAAC,iBAAiB,EAC3B,aAAa,EAAE,iBAAiB,EAChC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;YACvB,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,KAAK,CAAC,eAAe,EAAE,CAAC;YACxB,iBAAiB,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC,aAED,eAAM,SAAS,EAAC,uBAAuB,EAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,YAC9D,KAAK,GACD,EACP,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,oBAAoB,IAAC,OAAO,EAAE,UAAU,GAAI,EAC7C,KAAC,oBAAoB,IAAC,OAAO,EAAE,UAAU,GAAI,EAC7C,KAAC,iBAAiB,IAAC,KAAK,EAAC,cAAc,EAAC,OAAO,EAAE,OAAO,GAAI,IACxD,EACL,WAAW,IAAI,CACd,MAAC,IAAI,IACH,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,gBAAgB,EACzB,SAAS,EAAC,MAAM,aAEhB,KAAC,QAAQ,IACP,IAAI,EAAE,WAAW,EACjB,KAAK,EAAC,cAAc,EACpB,OAAO,EAAE,GAAG,EAAE;4BACZ,aAAa,EAAE,CAAC;4BAChB,gBAAgB,EAAE,CAAC;wBACrB,CAAC,GACD,EACF,KAAC,QAAQ,IACP,IAAI,EAAE,aAAa,EACnB,KAAK,EAAC,eAAe,EACrB,OAAO,EAAE,GAAG,EAAE;4BACZ,cAAc,EAAE,CAAC;4BACjB,gBAAgB,EAAE,CAAC;wBACrB,CAAC,GACD,IACG,CACR,IACG,CACP,CAAC;AACJ,CAAC","sourcesContent":["import { ArrowDownIcon } from \"@phosphor-icons/react/dist/csr/ArrowDown\";\nimport { ArrowUpIcon } from \"@phosphor-icons/react/dist/csr/ArrowUp\";\nimport { type ReactNode, useCallback } from \"react\";\nimport { Menu } from \"../menu/Menu\";\nimport { MenuItem } from \"../menu/MenuItem\";\nimport { useContextMenuPositionState } from \"../menu/useContextMenuState\";\nimport \"./WindowTitleBar.css\";\nimport { WindowCloseButton } from \"./WindowCloseButton\";\nimport { WindowMaximizeButton } from \"./WindowMaximizeButton\";\nimport { WindowMinimizeButton } from \"./WindowMinimizeButton\";\n\nexport interface WindowTitleBarAction {\n disabled?: boolean;\n icon: ReactNode;\n id: string;\n label: string;\n onClick: () => void;\n pressed?: boolean;\n}\n\nexport function WindowTitleBar({\n title,\n titleId,\n onPointerDown,\n onMinimize,\n onMaximize,\n onClose,\n onMoveForward,\n onMoveBackward,\n}: {\n title: string;\n titleId?: string | undefined;\n onPointerDown: (e: React.PointerEvent) => void;\n onMinimize: () => void;\n onMaximize: () => void;\n onClose: () => void;\n onMoveForward: () => void;\n onMoveBackward: () => void;\n}) {\n const { closeContextMenu, contextMenu, openContextMenuAt } =\n useContextMenuPositionState();\n\n const handlePointerDown = useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n const target = e.target;\n if (e.button !== 0) return;\n // Element, not HTMLElement: an icon inside a button (including the\n // portaled context menu, whose events bubble through React) is SVG.\n if (target instanceof Element && target.closest(\"button\")) return;\n onPointerDown(e);\n },\n [onPointerDown],\n );\n\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Window controls\"\n className=\"window-titlebar\"\n onPointerDown={handlePointerDown}\n onContextMenu={(event) => {\n event.preventDefault();\n event.stopPropagation();\n openContextMenuAt({ x: event.clientX, y: event.clientY });\n }}\n >\n <span className=\"window-titlebar-title\" id={titleId} title={title}>\n {title}\n </span>\n <div className=\"window-titlebar-buttons\">\n <WindowMinimizeButton onClick={onMinimize} />\n <WindowMaximizeButton onClick={onMaximize} />\n <WindowCloseButton label=\"Close window\" onClick={onClose} />\n </div>\n {contextMenu && (\n <Menu\n position={contextMenu}\n onClose={closeContextMenu}\n direction=\"down\"\n >\n <MenuItem\n icon={ArrowUpIcon}\n label=\"Move Forward\"\n onClick={() => {\n onMoveForward();\n closeContextMenu();\n }}\n />\n <MenuItem\n icon={ArrowDownIcon}\n label=\"Move Backward\"\n onClick={() => {\n onMoveBackward();\n closeContextMenu();\n }}\n />\n </Menu>\n )}\n </div>\n );\n}\n"]}
@@ -52,6 +52,12 @@
52
52
  cursor: pointer;
53
53
  }
54
54
 
55
+ /* A toggle that is on. Hover and focus still take the emphasis colors over it,
56
+ so the pressed tint reads as state rather than as another hover. */
57
+ .window-toolbar-button[aria-pressed="true"] {
58
+ background: color-mix(in srgb, currentColor 20%, transparent);
59
+ }
60
+
55
61
  .window-toolbar-button:hover:not(:disabled),
56
62
  .window-toolbar-button:focus-visible:not(:disabled) {
57
63
  background: var(--emphasis-surface);
@@ -1 +1 @@
1
- {"version":3,"file":"WindowToolBar.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/WindowToolBar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,qBAAqB,CAAC;AAC7B,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,mCAAmC,EACnC,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,SAAS,GAAG,KAAK,EACjB,QAAQ,EACR,eAAe,GAAG,KAAK,MAKrB,EAAE;IACJ,MAAM,UAAU,GAAG,wBAAwB,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAG,wBAAwB,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,wBAAwB,EAAE,CAAC;IAC5C,MAAM,mBAAmB,GAAG,mCAAmC,EAAE,CAAC;IAClE,MAAM,QAAQ,GAAG,UAAU,KAAK,IAAI,IAAI,CAAC,eAAe,IAAI,SAAS,CAAC,CAAC;IACvE,MAAM,SAAS,GACb,UAAU,KAAK,IAAI,IAAI,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/D,+EAA+E;IAC/E,4EAA4E;IAC5E,8EAA8E;IAC9E,6EAA6E;IAC7E,8EAA8E;IAC9E,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAChE,IAAI,aAAa,GAAG,cAAc,CAAC;IACnC,IAAI,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;QAChC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACxB,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;SAAM,IAAI,CAAC,SAAS,IAAI,mBAAmB,IAAI,aAAa,EAAE,CAAC;QAC9D,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACzB,aAAa,GAAG,KAAK,CAAC;IACxB,CAAC;IAED,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,SAAS,GAAG,UAAU,EAAE,KAAK,IAAI,MAAM,CAAC;IAE9C,OAAO,CACL,6BAAgB,SAAS,EAAC,SAAS,EAAC,gBAAgB,EAAC,IAAI,EAAC,SAAS,aACjE,cAAK,SAAS,EAAC,wBAAwB,YACpC,QAAQ,IAAI,CACX,gCACc,SAAS,EACrB,SAAS,EAAC,uBAAuB,EACjC,QAAQ,EAAE,UAAU,EAAE,QAAQ,IAAI,KAAK,EACvC,KAAK,EAAE,SAAS,EAChB,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,QAAQ,aAExC,KAAC,aAAa,yBAAa,IAAI,EAAE,EAAE,GAAI,EACvC,eAAM,SAAS,EAAC,2BAA2B,YAAE,SAAS,GAAQ,IACvD,CACV,GACG,EACN,cAAK,SAAS,EAAC,uBAAuB,GAAG,EACxC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CACrB,cAAK,SAAS,EAAC,wBAAwB,YACrC,KAAC,2BAA2B,IAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAC,uBAAuB,GACjC,GACE,CACP,IACG,CACP,CAAC;AACJ,CAAC","sourcesContent":["import { CaretLeftIcon } from \"@phosphor-icons/react/dist/csr/CaretLeft\";\nimport { useState } from \"react\";\nimport \"./WindowToolBar.css\";\nimport { WindowTitleBarActionButtons } from \"./WindowChromeActions\";\nimport {\n useWindowBackActionValue,\n useWindowTitleBarActions,\n useWindowToolbarReservationReleased,\n useWindowToolbarReserved,\n} from \"./WindowMenuContext\";\n\n/**\n * The window's toolbar row, sitting below the File/View menu bar and above the\n * body. It renders the same actions the routed app bar shows — the registered\n * {@link useWindowBackAction} on the left and {@link useWindowTitleBarAction}\n * icon buttons on the right — so a mini-app hosted in a window gets the same\n * toolbar chrome it gets in the routed shell.\n *\n * The left slot resolves exactly as `RoutedPaneAppBar` does: a registered back\n * action wins, and otherwise the button steps back through the host's own\n * history. `showHistoryBack` turns that fallback on for a window hosting a\n * routed mini-app, whose history is the window's Back stack (windows are not\n * backed by browser history); the fallback is omitted when that stack is empty.\n * Unlike the routed shell's paired Back/Forward controls, the window has no\n * adjacent history control whose stable placement would justify a disabled\n * Back button.\n *\n * Both surfaces read one shared registry (WindowMenuContext), so a mini-app\n * registers its actions once and they appear wherever it is hosted.\n *\n * A window whose app never registers toolbar chrome keeps a flush menu bar/body\n * (the row renders nothing). But once an app HAS shown chrome, the row stays\n * mounted and reserves its {@link WindowToolBar.css} min-height even when the\n * action set momentarily clears — on an action-less sub-route or a loading tick\n * where the app's `show` conditions are briefly false. Unmounting the row in\n * those windows would drop a full bar-height out of the flex column and shift\n * the body up, then back down when the actions re-register (visible flicker).\n *\n * An app that wants the row on every route — a blank bar where a route carries\n * no actions, rather than one that only appears after some route first shows\n * chrome — reserves it via {@link useWindowToolbarReservation} (the reserved row\n * still mounts a commit late, once that hook's effect registers, as all window\n * chrome does).\n */\nexport function WindowToolBar({\n canGoBack = false,\n onGoBack,\n showHistoryBack = false,\n}: {\n canGoBack?: boolean;\n onGoBack?: (() => void) | undefined;\n showHistoryBack?: boolean;\n} = {}) {\n const backAction = useWindowBackActionValue();\n const actions = useWindowTitleBarActions();\n const reserved = useWindowToolbarReserved();\n const reservationReleased = useWindowToolbarReservationReleased();\n const showBack = backAction !== null || (showHistoryBack && canGoBack);\n const hasChrome =\n backAction !== null || showHistoryBack || actions.length > 0;\n // Latch: this window's app has shown toolbar chrome at least once, so keep the\n // row reserved from here on rather than collapsing it on a transient empty.\n // Seed from the mount-time value so a window that already has chrome does not\n // latch during render at all; the render-phase set below catches chrome that\n // first appears after mount, without an effect's extra committed render pass.\n const [hasShownChrome, setHasShownChrome] = useState(hasChrome);\n let latchedChrome = hasShownChrome;\n if (hasChrome && !latchedChrome) {\n setHasShownChrome(true);\n latchedChrome = true;\n } else if (!hasChrome && reservationReleased && latchedChrome) {\n setHasShownChrome(false);\n latchedChrome = false;\n }\n\n if (!hasChrome && !latchedChrome && !reserved) {\n return null;\n }\n\n const backLabel = backAction?.label ?? \"Back\";\n\n return (\n <div aria-label=\"Toolbar\" className=\"window-toolbar\" role=\"toolbar\">\n <div className=\"window-toolbar-primary\">\n {showBack && (\n <button\n aria-label={backLabel}\n className=\"window-toolbar-button\"\n disabled={backAction?.disabled ?? false}\n title={backLabel}\n type=\"button\"\n onClick={backAction?.onClick ?? onGoBack}\n >\n <CaretLeftIcon aria-hidden size={18} />\n <span className=\"window-toolbar-back-label\">{backLabel}</span>\n </button>\n )}\n </div>\n <div className=\"window-toolbar-spacer\" />\n {actions.length > 0 && (\n <div className=\"window-toolbar-actions\">\n <WindowTitleBarActionButtons\n actions={actions}\n className=\"window-toolbar-button\"\n />\n </div>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"WindowToolBar.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/WindowToolBar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,qBAAqB,CAAC;AAC7B,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,mCAAmC,EACnC,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,SAAS,GAAG,KAAK,EACjB,QAAQ,EACR,eAAe,GAAG,KAAK,MAKrB,EAAE;IACJ,MAAM,UAAU,GAAG,wBAAwB,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAG,wBAAwB,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,wBAAwB,EAAE,CAAC;IAC5C,MAAM,mBAAmB,GAAG,mCAAmC,EAAE,CAAC;IAClE,MAAM,QAAQ,GAAG,UAAU,KAAK,IAAI,IAAI,CAAC,eAAe,IAAI,SAAS,CAAC,CAAC;IACvE,MAAM,SAAS,GACb,UAAU,KAAK,IAAI,IAAI,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/D,+EAA+E;IAC/E,4EAA4E;IAC5E,8EAA8E;IAC9E,6EAA6E;IAC7E,8EAA8E;IAC9E,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAChE,IAAI,aAAa,GAAG,cAAc,CAAC;IACnC,IAAI,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;QAChC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACxB,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;SAAM,IAAI,CAAC,SAAS,IAAI,mBAAmB,IAAI,aAAa,EAAE,CAAC;QAC9D,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACzB,aAAa,GAAG,KAAK,CAAC;IACxB,CAAC;IAED,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,SAAS,GAAG,UAAU,EAAE,KAAK,IAAI,MAAM,CAAC;IAE9C,OAAO,CACL,6BAAgB,SAAS,EAAC,SAAS,EAAC,gBAAgB,EAAC,IAAI,EAAC,SAAS,aACjE,cAAK,SAAS,EAAC,wBAAwB,YACpC,QAAQ,IAAI,CACX,gCACc,SAAS,EACrB,SAAS,EAAC,uBAAuB,EACjC,QAAQ,EAAE,UAAU,EAAE,QAAQ,IAAI,KAAK,EACvC,KAAK,EAAE,SAAS,EAChB,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,QAAQ,aAExC,KAAC,aAAa,yBAAa,IAAI,EAAE,EAAE,GAAI,EACvC,eAAM,SAAS,EAAC,2BAA2B,YAAE,SAAS,GAAQ,IACvD,CACV,GACG,EACN,cAAK,SAAS,EAAC,uBAAuB,GAAG,EACxC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CACrB,cAAK,SAAS,EAAC,wBAAwB,YACrC,KAAC,2BAA2B,IAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAC,uBAAuB,GACjC,GACE,CACP,IACG,CACP,CAAC;AACJ,CAAC","sourcesContent":["import { CaretLeftIcon } from \"@phosphor-icons/react/dist/csr/CaretLeft\";\nimport { useState } from \"react\";\nimport \"./WindowToolBar.css\";\nimport { WindowTitleBarActionButtons } from \"./WindowChromeActions\";\nimport {\n useWindowBackActionValue,\n useWindowTitleBarActions,\n useWindowToolbarReservationReleased,\n useWindowToolbarReserved,\n} from \"./WindowMenuContext\";\n\n/**\n * The window's toolbar row, sitting below the File/View menu bar and above the\n * body. It renders the same actions the routed app bar shows — the registered\n * {@link useWindowBackAction} on the left and {@link useWindowTitleBarAction}\n * icon buttons on the right — so a mini-app hosted in a window gets the same\n * toolbar chrome it gets in the routed shell.\n *\n * The left slot resolves exactly as `RoutedPaneAppBar` does: a registered back\n * action wins, and otherwise the button steps back through the host's own\n * history. `showHistoryBack` turns that fallback on for a window hosting a\n * routed mini-app, whose history is the window's Back stack (windows are not\n * backed by browser history); the fallback is omitted when that stack is empty.\n * Unlike the routed shell's paired Back/Forward controls, the window has no\n * adjacent history control whose stable placement would justify a disabled\n * Back button.\n *\n * Both surfaces read one shared registry (WindowMenuContext), so a mini-app\n * registers its actions once and they appear wherever it is hosted.\n *\n * A window whose app never registers toolbar chrome keeps a flush menu bar/body\n * (the row renders nothing). But once an app HAS shown chrome, the row stays\n * mounted and reserves its {@link WindowToolBar.css} min-height even when the\n * action set momentarily clears — on an action-less sub-route or a loading tick\n * where the app's `show` conditions are briefly false. Unmounting the row in\n * those windows would drop a full bar-height out of the flex column and shift\n * the body up, then back down when the actions re-register (visible flicker).\n *\n * An app that wants the row on every route — a blank bar where a route carries\n * no actions, rather than one that only appears after some route first shows\n * chrome — reserves it via {@link useWindowToolbarReservation} (the reserved row\n * still mounts a commit late, once that hook's effect registers, as all window\n * chrome does).\n */\nexport function WindowToolBar({\n canGoBack = false,\n onGoBack,\n showHistoryBack = false,\n}: {\n canGoBack?: boolean;\n onGoBack?: (() => void) | undefined;\n showHistoryBack?: boolean;\n} = {}) {\n const backAction = useWindowBackActionValue();\n const actions = useWindowTitleBarActions();\n const reserved = useWindowToolbarReserved();\n const reservationReleased = useWindowToolbarReservationReleased();\n const showBack = backAction !== null || (showHistoryBack && canGoBack);\n const hasChrome =\n backAction !== null || showHistoryBack || actions.length > 0;\n // Latch: this window's app has shown toolbar chrome at least once, so keep the\n // row reserved from here on rather than collapsing it on a transient empty.\n // Seed from the mount-time value so a window that already has chrome does not\n // latch during render at all; the render-phase set below catches chrome that\n // first appears after mount, without an effect's extra committed render pass.\n const [hasShownChrome, setHasShownChrome] = useState(hasChrome);\n let latchedChrome = hasShownChrome;\n if (hasChrome && !latchedChrome) {\n setHasShownChrome(true);\n latchedChrome = true;\n } else if (!hasChrome && reservationReleased && latchedChrome) {\n setHasShownChrome(false);\n latchedChrome = false;\n }\n\n if (!hasChrome && !latchedChrome && !reserved) {\n return null;\n }\n\n const backLabel = backAction?.label ?? \"Back\";\n\n return (\n <div aria-label=\"Toolbar\" className=\"window-toolbar\" role=\"toolbar\">\n <div className=\"window-toolbar-primary\">\n {showBack && (\n <button\n aria-label={backLabel}\n className=\"window-toolbar-button\"\n disabled={backAction?.disabled ?? false}\n title={backLabel}\n type=\"button\"\n onClick={backAction?.onClick ?? onGoBack}\n >\n <CaretLeftIcon aria-hidden size={18} />\n <span className=\"window-toolbar-back-label\">{backLabel}</span>\n </button>\n )}\n </div>\n <div className=\"window-toolbar-spacer\" />\n {actions.length > 0 && (\n <div className=\"window-toolbar-actions\">\n <WindowTitleBarActionButtons\n actions={actions}\n className=\"window-toolbar-button\"\n />\n </div>\n )}\n </div>\n );\n}\n"]}
@@ -1,12 +1,12 @@
1
1
  import { type PointerEvent as ReactPointerEvent, type RefObject } from "react";
2
- import type { ResizeCorner } from "./WindowResizeHandle.js";
2
+ import type { ResizeEdge } from "./WindowResizeHandle.js";
3
3
  import { type WindowEntry, type WindowPosition, type WindowSize } from "./WindowStateProvider/index.js";
4
4
  import { type LiveGeometry } from "./windowGeometry.js";
5
5
  export declare function useWindowGeometry(entry: WindowEntry, maximized: boolean, windowRef: RefObject<HTMLElement | null>): {
6
6
  commit: () => void;
7
7
  hold: (holding: boolean) => void;
8
8
  handlePointerDown: (event: ReactPointerEvent) => void;
9
- handleResizePointerDown: (event: ReactPointerEvent, corner: ResizeCorner) => void;
9
+ handleResizePointerDown: (event: ReactPointerEvent, edge: ResizeEdge) => void;
10
10
  position: WindowPosition | null;
11
11
  size: WindowSize | null;
12
12
  grow: (deltaWidth: number, deltaHeight: number) => void;
@@ -137,12 +137,12 @@ function capturePointer(event) {
137
137
  // Not an active pointer; the document listeners still track the gesture.
138
138
  }
139
139
  }
140
- // Starts a drag from the title bar or a resize from a corner. The gesture
141
- // itself is tracked on the document by useWindowPointerTracking.
140
+ // Starts a drag from the title bar or a resize from an edge or corner. The
141
+ // gesture itself is tracked on the document by useWindowPointerTracking.
142
142
  function useGestureStarts(windowRef, maximized, position, dragging, resizing) {
143
143
  const handlePointerDown = useCallback((event) => {
144
144
  // One gesture at a time: a second pointer pressing the title bar or a
145
- // corner mid-gesture must not take it over.
145
+ // resize handle mid-gesture must not take it over.
146
146
  if (!position || maximized || dragging.current || resizing.current) {
147
147
  return;
148
148
  }
@@ -153,7 +153,7 @@ function useGestureStarts(windowRef, maximized, position, dragging, resizing) {
153
153
  };
154
154
  capturePointer(event);
155
155
  }, [dragging, maximized, position, resizing]);
156
- const handleResizePointerDown = useCallback((event, corner) => {
156
+ const handleResizePointerDown = useCallback((event, edge) => {
157
157
  if (maximized ||
158
158
  !position ||
159
159
  !windowRef.current ||
@@ -167,7 +167,7 @@ function useGestureStarts(windowRef, maximized, position, dragging, resizing) {
167
167
  const computed = getComputedStyle(el);
168
168
  const borderBox = computed.boxSizing === "border-box";
169
169
  resizing.current = {
170
- corner,
170
+ edge,
171
171
  pointerId: event.pointerId,
172
172
  startX: event.clientX,
173
173
  startY: event.clientY,
@@ -1 +1 @@
1
- {"version":3,"file":"useWindowGeometry.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/useWindowGeometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,WAAW,EACX,SAAS,EACT,MAAM,EACN,QAAQ,GACT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EACL,gBAAgB,GAIjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EAEnB,UAAU,EACV,SAAS,EACT,2BAA2B,GAG5B,MAAM,kBAAkB,CAAC;AAE1B,+EAA+E;AAC/E,2EAA2E;AAC3E,uEAAuE;AACvE,SAAS,wBAAwB,CAC/B,SAAwC,EACxC,QAAkD,EAClD,QAAoD,EACpD,KAA+C,EAC/C,WAA4C,EAC5C,OAA2C,EAC3C,MAAkB;IAElB,SAAS,CAAC,GAAG,EAAE;QACb,wEAAwE;QACxE,0CAA0C;QAC1C,SAAS,gBAAgB,CAAC,KAAmB;YAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC;YACrD,OAAO,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,CAAC;QACnE,CAAC;QAED,SAAS,iBAAiB,CAAC,KAAmB;YAC5C,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7B,OAAO;YACT,CAAC;YACD,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACrB,MAAM,SAAS,GAAG,2BAA2B,CAC3C,QAAQ,CAAC,OAAO,EAChB,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,OAAO,EACb,SAAS,CAAC,OAAO,EAAE,aAAa,IAAI,IAAI,CACzC,CAAC;gBACF,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;gBAChC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBACxB,OAAO;YACT,CAAC;YAED,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACrB,WAAW,CACT,KAAK,CACH,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EACxC,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CACzC,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,SAAS,gBAAgB,CAAC,KAAmB;YAC3C,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7B,OAAO;YACT,CAAC;YACD,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;YACxB,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;YACxB,MAAM,EAAE,CAAC;QACX,CAAC;QAED,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;QAC5D,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;QACzD,QAAQ,CAAC,gBAAgB,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC;QAC7D,QAAQ,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAC;QAClE,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,mBAAmB,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;YAC/D,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;YAC5D,QAAQ,CAAC,mBAAmB,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC;YAChE,QAAQ,CAAC,mBAAmB,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAC;QACvE,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,eAAe,CAAC,KAAkB;IACzC,MAAM,EAAE,WAAW,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAC3C,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAwB,IAAI,CAAC,CAAC;IAC3E,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAoB,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IAC7E,sEAAsE;IACtE,MAAM,IAAI,GAAG,MAAM,CAAe;QAChC,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI;KACzB,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,KAAqB,EAAE,EAAE;QACxD,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC9B,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,KAAwB,EAAE,EAAE;QACvD,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC;QAC1B,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9B,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QAChD,IAAI,iBAAiB,EAAE,CAAC;YACtB,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE;gBACpB,QAAQ,EAAE,iBAAiB;gBAC3B,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,SAAS;aACrC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;IAE5B,yEAAyE;IACzE,6EAA6E;IAC7E,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IAC9B,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAE1B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAChE,CAAC;AAED,6EAA6E;AAC7E,wEAAwE;AACxE,SAAS,kBAAkB,CACzB,SAAwC,EACxC,SAAkB,EAClB,IAAoC,EACpC,KAA+C,EAC/C,WAA4C,EAC5C,OAA2C;IAE3C,MAAM,KAAK,GAAG,WAAW,CACvB,CAAC,MAAc,EAAE,MAAc,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QACtC,IAAI,CAAC,OAAO,IAAI,SAAS,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QACD,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAC7D,CAAC,EACD,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CACtC,CAAC;IAEF,MAAM,IAAI,GAAG,WAAW,CACtB,CAAC,UAAkB,EAAE,WAAmB,EAAE,EAAE;QAC1C,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QACtC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,IAAI,SAAS,EAAE,CAAC;YACtC,OAAO;QACT,CAAC;QACD,sEAAsE;QACtE,0EAA0E;QAC1E,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;QACpC,MAAM,IAAI,GAAG,SAAS;YACpB,CAAC,CAAC;gBACE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC;gBAC9C,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC;aAC5C;YACH,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;QACjE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC;QACxC,MAAM,QAAQ,GAAG,SAAS;YACxB,CAAC,CAAC,SAAS,CAAC,WAAW,GAAG,OAAO,CAAC,CAAC;YACnC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAC7B,MAAM,SAAS,GAAG,SAAS;YACzB,CAAC,CAAC,SAAS,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC;YACpC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAC7B,OAAO,CAAC;YACN,MAAM,EAAE,IAAI,CAAC,GAAG,CACd,UAAU,EACV,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,WAAW,EAAE,SAAS,CAAC,CAC/C;YACD,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,UAAU,EAAE,QAAQ,CAAC,CAAC;SACxE,CAAC,CAAC;IACL,CAAC,EACD,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CACtC,CAAC;IAEF,MAAM,QAAQ,GAAG,WAAW,CAC1B,GAAiB,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,EACzC,CAAC,IAAI,CAAC,CACP,CAAC;IACF,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,KAAmB,EAAE,EAAE;QACtB,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC,EACD,CAAC,WAAW,EAAE,OAAO,CAAC,CACvB,CAAC;IAEF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC5C,CAAC;AAED,8EAA8E;AAC9E,6EAA6E;AAC7E,yEAAyE;AACzE,SAAS,cAAc,CAAC,KAAwB;IAC9C,IAAI,CAAC;QACH,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,iEAAiE;AACjE,SAAS,gBAAgB,CACvB,SAAwC,EACxC,SAAkB,EAClB,QAA+B,EAC/B,QAAkD,EAClD,QAAoD;IAEpD,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,KAAwB,EAAE,EAAE;QAC3B,sEAAsE;QACtE,4CAA4C;QAC5C,IAAI,CAAC,QAAQ,IAAI,SAAS,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACnE,OAAO;QACT,CAAC;QACD,QAAQ,CAAC,OAAO,GAAG;YACjB,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC;YACnC,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC;YACnC,SAAS,EAAE,KAAK,CAAC,SAAS;SAC3B,CAAC;QACF,cAAc,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC,EACD,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAC1C,CAAC;IAEF,MAAM,uBAAuB,GAAG,WAAW,CACzC,CAAC,KAAwB,EAAE,MAAoB,EAAE,EAAE;QACjD,IACE,SAAS;YACT,CAAC,QAAQ;YACT,CAAC,SAAS,CAAC,OAAO;YAClB,QAAQ,CAAC,OAAO;YAChB,QAAQ,CAAC,OAAO,EAChB,CAAC;YACD,OAAO;QACT,CAAC;QACD,KAAK,CAAC,eAAe,EAAE,CAAC;QACxB,cAAc,CAAC,KAAK,CAAC,CAAC;QACtB,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC;QAC7B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,KAAK,YAAY,CAAC;QACtD,QAAQ,CAAC,OAAO,GAAG;YACjB,MAAM;YACN,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,KAAK,CAAC,OAAO;YACrB,MAAM,EAAE,KAAK,CAAC,OAAO;YACrB,SAAS,EAAE,QAAQ,CAAC,CAAC;YACrB,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACpB,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC;YACtC,WAAW,EAAE,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC;YACxC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,GAAG,EAAE,CAAC,WAAW;YACxD,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,GAAG,EAAE,CAAC,YAAY;SAC3D,CAAC;IACJ,CAAC,EACD,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAC3C,CAAC;IAEF,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,KAAkB,EAClB,SAAkB,EAClB,SAAwC;IAExC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,GAC1D,eAAe,CAAC,KAAK,CAAC,CAAC;IACzB,MAAM,QAAQ,GAAG,MAAM,CAAyB,IAAI,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,MAAM,CAA2B,IAAI,CAAC,CAAC;IACxD,0EAA0E;IAC1E,yEAAyE;IACzE,kEAAkE;IAClE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YACpC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YAC3C,OAAO;QACT,CAAC;QACD,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;QAC5B,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,EAAE;QACD,KAAK,CAAC,SAAS;QACf,KAAK,CAAC,QAAQ;QACd,KAAK,CAAC,IAAI;QACV,SAAS;QACT,WAAW;QACX,OAAO;KACR,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,WAAW,CACvB,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CACvB,mBAAmB,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EACjE,CAAC,IAAI,EAAE,SAAS,CAAC,CAClB,CAAC;IAEF,MAAM,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC;QAC/B,KAAK;QACL,MAAM;QACN,QAAQ;QACR,KAAK;QACL,IAAI;QACJ,QAAQ;QACR,WAAW;QACX,IAAI;QACJ,SAAS;KACV,CAAC,CAAC;IAEH,wEAAwE;IACxE,6EAA6E;IAC7E,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE;QACrC,MAAM,EAAE,CAAC;QACT,IAAI,CAAC,KAAK,CAAC,CAAC;IACd,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAEnB,wBAAwB,CACtB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,WAAW,EACX,OAAO,EACP,aAAa,CACd,CAAC;IAEF,MAAM,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,GAAG,gBAAgB,CACrE,SAAS,EACT,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,QAAQ,CACT,CAAC;IAEF,MAAM,OAAO,GAAG,kBAAkB,CAChC,SAAS,EACT,SAAS,EACT,IAAI,EACJ,KAAK,EACL,WAAW,EACX,OAAO,CACR,CAAC;IAEF,OAAO;QACL,GAAG,OAAO;QACV,MAAM;QACN,IAAI;QACJ,iBAAiB;QACjB,uBAAuB;QACvB,QAAQ;QACR,IAAI;KACL,CAAC;AACJ,CAAC","sourcesContent":["import {\n type MutableRefObject,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useWindowLayout } from \"./useWindowLayout\";\nimport type { ResizeCorner } from \"./WindowResizeHandle\";\nimport {\n useWindowActions,\n type WindowEntry,\n type WindowPosition,\n type WindowSize,\n} from \"./WindowStateProvider\";\nimport {\n clampWindowPosition,\n type LiveGeometry,\n MIN_HEIGHT,\n MIN_WIDTH,\n resizeWindowWithinContainer,\n type WindowDragState,\n type WindowResizeState,\n} from \"./windowGeometry\";\n\n// Pointer events cover mouse, touch, and pen alike. The live geometry stays in\n// component state while a gesture runs, so only this window re-renders per\n// frame; the gesture's end commits it to the shared window state once.\nfunction useWindowPointerTracking(\n windowRef: RefObject<HTMLElement | null>,\n dragging: MutableRefObject<WindowDragState | null>,\n resizing: MutableRefObject<WindowResizeState | null>,\n clamp: (x: number, y: number) => WindowPosition,\n setPosition: (value: WindowPosition) => void,\n setSize: (value: WindowSize | null) => void,\n finish: () => void,\n) {\n useEffect(() => {\n // Only the pointer that started a gesture drives it, so a second finger\n // cannot move the window or end the drag.\n function isGesturePointer(event: PointerEvent) {\n const gesture = resizing.current ?? dragging.current;\n return gesture !== null && gesture.pointerId === event.pointerId;\n }\n\n function handlePointerMove(event: PointerEvent) {\n if (!isGesturePointer(event)) {\n return;\n }\n if (resizing.current) {\n const nextFrame = resizeWindowWithinContainer(\n resizing.current,\n event.clientX,\n event.clientY,\n windowRef.current?.parentElement ?? null,\n );\n setPosition(nextFrame.position);\n setSize(nextFrame.size);\n return;\n }\n\n if (dragging.current) {\n setPosition(\n clamp(\n event.clientX - dragging.current.offsetX,\n event.clientY - dragging.current.offsetY,\n ),\n );\n }\n }\n\n function handlePointerEnd(event: PointerEvent) {\n if (!isGesturePointer(event)) {\n return;\n }\n dragging.current = null;\n resizing.current = null;\n finish();\n }\n\n document.addEventListener(\"pointermove\", handlePointerMove);\n document.addEventListener(\"pointerup\", handlePointerEnd);\n document.addEventListener(\"pointercancel\", handlePointerEnd);\n document.addEventListener(\"lostpointercapture\", handlePointerEnd);\n return () => {\n document.removeEventListener(\"pointermove\", handlePointerMove);\n document.removeEventListener(\"pointerup\", handlePointerEnd);\n document.removeEventListener(\"pointercancel\", handlePointerEnd);\n document.removeEventListener(\"lostpointercapture\", handlePointerEnd);\n };\n }, [clamp, dragging, finish, resizing, setPosition, setSize, windowRef]);\n}\n\nfunction useLiveGeometry(entry: WindowEntry) {\n const { setGeometry } = useWindowActions();\n const [position, setPositionState] = useState<WindowPosition | null>(null);\n const [size, setSizeState] = useState<WindowSize | null>(entry.size ?? null);\n // Mirrors the live state so a gesture's end commits the latest frame.\n const live = useRef<LiveGeometry>({\n position: null,\n size: entry.size ?? null,\n });\n\n const setPosition = useCallback((value: WindowPosition) => {\n live.current.position = value;\n setPositionState(value);\n }, []);\n const setSize = useCallback((value: WindowSize | null) => {\n live.current.size = value;\n setSizeState(value);\n }, []);\n const commit = useCallback(() => {\n const committedPosition = live.current.position;\n if (committedPosition) {\n setGeometry(entry.id, {\n position: committedPosition,\n size: live.current.size ?? undefined,\n });\n }\n }, [entry.id, setGeometry]);\n\n // The committed size is the source of truth between gestures: a restored\n // layout or host call applies it, and clearing it restores the default size.\n useEffect(() => {\n setSize(entry.size ?? null);\n }, [entry.size, setSize]);\n\n return { commit, live, position, setPosition, setSize, size };\n}\n\n// Stepwise geometry for keyboard move and resize. Steps stay local until the\n// caller commits, like a pointer gesture; restore puts a snapshot back.\nfunction useSteppedGeometry(\n windowRef: RefObject<HTMLElement | null>,\n maximized: boolean,\n live: MutableRefObject<LiveGeometry>,\n clamp: (x: number, y: number) => WindowPosition,\n setPosition: (value: WindowPosition) => void,\n setSize: (value: WindowSize | null) => void,\n) {\n const nudge = useCallback(\n (deltaX: number, deltaY: number) => {\n const current = live.current.position;\n if (!current || maximized) {\n return;\n }\n setPosition(clamp(current.x + deltaX, current.y + deltaY));\n },\n [clamp, live, maximized, setPosition],\n );\n\n const grow = useCallback(\n (deltaWidth: number, deltaHeight: number) => {\n const element = windowRef.current;\n const current = live.current.position;\n if (!element || !current || maximized) {\n return;\n }\n // Step from the size on screen: a requested size below the stylesheet\n // minimums renders at the minimum, so growing from it would show nothing.\n const requested = live.current.size;\n const base = requested\n ? {\n height: Math.max(MIN_HEIGHT, requested.height),\n width: Math.max(MIN_WIDTH, requested.width),\n }\n : { height: element.offsetHeight, width: element.offsetWidth };\n const container = element.parentElement;\n const maxWidth = container\n ? container.clientWidth - current.x\n : Number.POSITIVE_INFINITY;\n const maxHeight = container\n ? container.clientHeight - current.y\n : Number.POSITIVE_INFINITY;\n setSize({\n height: Math.max(\n MIN_HEIGHT,\n Math.min(base.height + deltaHeight, maxHeight),\n ),\n width: Math.max(MIN_WIDTH, Math.min(base.width + deltaWidth, maxWidth)),\n });\n },\n [live, maximized, setSize, windowRef],\n );\n\n const snapshot = useCallback(\n (): LiveGeometry => ({ ...live.current }),\n [live],\n );\n const restore = useCallback(\n (saved: LiveGeometry) => {\n if (saved.position) {\n setPosition(saved.position);\n }\n setSize(saved.size);\n },\n [setPosition, setSize],\n );\n\n return { grow, nudge, restore, snapshot };\n}\n\n// Keeps a gesture's pointer events coming to the window even when the pointer\n// passes over an iframe, whose document would otherwise swallow the release.\n// Synthetic events carry no active pointer, so a failed capture is fine.\nfunction capturePointer(event: ReactPointerEvent) {\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n // Not an active pointer; the document listeners still track the gesture.\n }\n}\n\n// Starts a drag from the title bar or a resize from a corner. The gesture\n// itself is tracked on the document by useWindowPointerTracking.\nfunction useGestureStarts(\n windowRef: RefObject<HTMLElement | null>,\n maximized: boolean,\n position: WindowPosition | null,\n dragging: MutableRefObject<WindowDragState | null>,\n resizing: MutableRefObject<WindowResizeState | null>,\n) {\n const handlePointerDown = useCallback(\n (event: ReactPointerEvent) => {\n // One gesture at a time: a second pointer pressing the title bar or a\n // corner mid-gesture must not take it over.\n if (!position || maximized || dragging.current || resizing.current) {\n return;\n }\n dragging.current = {\n offsetX: event.clientX - position.x,\n offsetY: event.clientY - position.y,\n pointerId: event.pointerId,\n };\n capturePointer(event);\n },\n [dragging, maximized, position, resizing],\n );\n\n const handleResizePointerDown = useCallback(\n (event: ReactPointerEvent, corner: ResizeCorner) => {\n if (\n maximized ||\n !position ||\n !windowRef.current ||\n dragging.current ||\n resizing.current\n ) {\n return;\n }\n event.stopPropagation();\n capturePointer(event);\n const el = windowRef.current;\n const computed = getComputedStyle(el);\n const borderBox = computed.boxSizing === \"border-box\";\n resizing.current = {\n corner,\n pointerId: event.pointerId,\n startX: event.clientX,\n startY: event.clientY,\n startLeft: position.x,\n startTop: position.y,\n startWidth: parseFloat(computed.width),\n startHeight: parseFloat(computed.height),\n borderX: borderBox ? 0 : el.offsetWidth - el.clientWidth,\n borderY: borderBox ? 0 : el.offsetHeight - el.clientHeight,\n };\n },\n [maximized, position, resizing, windowRef],\n );\n\n return { handlePointerDown, handleResizePointerDown };\n}\n\nexport function useWindowGeometry(\n entry: WindowEntry,\n maximized: boolean,\n windowRef: RefObject<HTMLElement | null>,\n) {\n const { commit, live, position, setPosition, setSize, size } =\n useLiveGeometry(entry);\n const dragging = useRef<WindowDragState | null>(null);\n const resizing = useRef<WindowResizeState | null>(null);\n // Maximizing or minimizing mid-gesture (a second touch on the title bar's\n // controls) abandons the gesture: its frames were measured at the normal\n // size, so the live geometry goes back to the committed geometry.\n useEffect(() => {\n if (!(maximized || entry.minimized)) {\n return;\n }\n if (!dragging.current && !resizing.current) {\n return;\n }\n dragging.current = null;\n resizing.current = null;\n setSize(entry.size ?? null);\n if (entry.position) {\n setPosition(entry.position);\n }\n }, [\n entry.minimized,\n entry.position,\n entry.size,\n maximized,\n setPosition,\n setSize,\n ]);\n const clamp = useCallback(\n (x: number, y: number) =>\n clampWindowPosition(windowRef.current, x, y, live.current.size),\n [live, windowRef],\n );\n\n const { hold } = useWindowLayout({\n clamp,\n commit,\n dragging,\n entry,\n live,\n resizing,\n setPosition,\n size,\n windowRef,\n });\n\n // A finished gesture commits its geometry, then runs any layout it held\n // off (a surface resize mid-gesture), even when the geometry did not change.\n const finishGesture = useCallback(() => {\n commit();\n hold(false);\n }, [commit, hold]);\n\n useWindowPointerTracking(\n windowRef,\n dragging,\n resizing,\n clamp,\n setPosition,\n setSize,\n finishGesture,\n );\n\n const { handlePointerDown, handleResizePointerDown } = useGestureStarts(\n windowRef,\n maximized,\n position,\n dragging,\n resizing,\n );\n\n const stepped = useSteppedGeometry(\n windowRef,\n maximized,\n live,\n clamp,\n setPosition,\n setSize,\n );\n\n return {\n ...stepped,\n commit,\n hold,\n handlePointerDown,\n handleResizePointerDown,\n position,\n size,\n };\n}\n"]}
1
+ {"version":3,"file":"useWindowGeometry.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/useWindowGeometry.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type MutableRefObject,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useWindowLayout } from \"./useWindowLayout\";\nimport type { ResizeEdge } from \"./WindowResizeHandle\";\nimport {\n useWindowActions,\n type WindowEntry,\n type WindowPosition,\n type WindowSize,\n} from \"./WindowStateProvider\";\nimport {\n clampWindowPosition,\n type LiveGeometry,\n MIN_HEIGHT,\n MIN_WIDTH,\n resizeWindowWithinContainer,\n type WindowDragState,\n type WindowResizeState,\n} from \"./windowGeometry\";\n\n// Pointer events cover mouse, touch, and pen alike. The live geometry stays in\n// component state while a gesture runs, so only this window re-renders per\n// frame; the gesture's end commits it to the shared window state once.\nfunction useWindowPointerTracking(\n windowRef: RefObject<HTMLElement | null>,\n dragging: MutableRefObject<WindowDragState | null>,\n resizing: MutableRefObject<WindowResizeState | null>,\n clamp: (x: number, y: number) => WindowPosition,\n setPosition: (value: WindowPosition) => void,\n setSize: (value: WindowSize | null) => void,\n finish: () => void,\n) {\n useEffect(() => {\n // Only the pointer that started a gesture drives it, so a second finger\n // cannot move the window or end the drag.\n function isGesturePointer(event: PointerEvent) {\n const gesture = resizing.current ?? dragging.current;\n return gesture !== null && gesture.pointerId === event.pointerId;\n }\n\n function handlePointerMove(event: PointerEvent) {\n if (!isGesturePointer(event)) {\n return;\n }\n if (resizing.current) {\n const nextFrame = resizeWindowWithinContainer(\n resizing.current,\n event.clientX,\n event.clientY,\n windowRef.current?.parentElement ?? null,\n );\n setPosition(nextFrame.position);\n setSize(nextFrame.size);\n return;\n }\n\n if (dragging.current) {\n setPosition(\n clamp(\n event.clientX - dragging.current.offsetX,\n event.clientY - dragging.current.offsetY,\n ),\n );\n }\n }\n\n function handlePointerEnd(event: PointerEvent) {\n if (!isGesturePointer(event)) {\n return;\n }\n dragging.current = null;\n resizing.current = null;\n finish();\n }\n\n document.addEventListener(\"pointermove\", handlePointerMove);\n document.addEventListener(\"pointerup\", handlePointerEnd);\n document.addEventListener(\"pointercancel\", handlePointerEnd);\n document.addEventListener(\"lostpointercapture\", handlePointerEnd);\n return () => {\n document.removeEventListener(\"pointermove\", handlePointerMove);\n document.removeEventListener(\"pointerup\", handlePointerEnd);\n document.removeEventListener(\"pointercancel\", handlePointerEnd);\n document.removeEventListener(\"lostpointercapture\", handlePointerEnd);\n };\n }, [clamp, dragging, finish, resizing, setPosition, setSize, windowRef]);\n}\n\nfunction useLiveGeometry(entry: WindowEntry) {\n const { setGeometry } = useWindowActions();\n const [position, setPositionState] = useState<WindowPosition | null>(null);\n const [size, setSizeState] = useState<WindowSize | null>(entry.size ?? null);\n // Mirrors the live state so a gesture's end commits the latest frame.\n const live = useRef<LiveGeometry>({\n position: null,\n size: entry.size ?? null,\n });\n\n const setPosition = useCallback((value: WindowPosition) => {\n live.current.position = value;\n setPositionState(value);\n }, []);\n const setSize = useCallback((value: WindowSize | null) => {\n live.current.size = value;\n setSizeState(value);\n }, []);\n const commit = useCallback(() => {\n const committedPosition = live.current.position;\n if (committedPosition) {\n setGeometry(entry.id, {\n position: committedPosition,\n size: live.current.size ?? undefined,\n });\n }\n }, [entry.id, setGeometry]);\n\n // The committed size is the source of truth between gestures: a restored\n // layout or host call applies it, and clearing it restores the default size.\n useEffect(() => {\n setSize(entry.size ?? null);\n }, [entry.size, setSize]);\n\n return { commit, live, position, setPosition, setSize, size };\n}\n\n// Stepwise geometry for keyboard move and resize. Steps stay local until the\n// caller commits, like a pointer gesture; restore puts a snapshot back.\nfunction useSteppedGeometry(\n windowRef: RefObject<HTMLElement | null>,\n maximized: boolean,\n live: MutableRefObject<LiveGeometry>,\n clamp: (x: number, y: number) => WindowPosition,\n setPosition: (value: WindowPosition) => void,\n setSize: (value: WindowSize | null) => void,\n) {\n const nudge = useCallback(\n (deltaX: number, deltaY: number) => {\n const current = live.current.position;\n if (!current || maximized) {\n return;\n }\n setPosition(clamp(current.x + deltaX, current.y + deltaY));\n },\n [clamp, live, maximized, setPosition],\n );\n\n const grow = useCallback(\n (deltaWidth: number, deltaHeight: number) => {\n const element = windowRef.current;\n const current = live.current.position;\n if (!element || !current || maximized) {\n return;\n }\n // Step from the size on screen: a requested size below the stylesheet\n // minimums renders at the minimum, so growing from it would show nothing.\n const requested = live.current.size;\n const base = requested\n ? {\n height: Math.max(MIN_HEIGHT, requested.height),\n width: Math.max(MIN_WIDTH, requested.width),\n }\n : { height: element.offsetHeight, width: element.offsetWidth };\n const container = element.parentElement;\n const maxWidth = container\n ? container.clientWidth - current.x\n : Number.POSITIVE_INFINITY;\n const maxHeight = container\n ? container.clientHeight - current.y\n : Number.POSITIVE_INFINITY;\n setSize({\n height: Math.max(\n MIN_HEIGHT,\n Math.min(base.height + deltaHeight, maxHeight),\n ),\n width: Math.max(MIN_WIDTH, Math.min(base.width + deltaWidth, maxWidth)),\n });\n },\n [live, maximized, setSize, windowRef],\n );\n\n const snapshot = useCallback(\n (): LiveGeometry => ({ ...live.current }),\n [live],\n );\n const restore = useCallback(\n (saved: LiveGeometry) => {\n if (saved.position) {\n setPosition(saved.position);\n }\n setSize(saved.size);\n },\n [setPosition, setSize],\n );\n\n return { grow, nudge, restore, snapshot };\n}\n\n// Keeps a gesture's pointer events coming to the window even when the pointer\n// passes over an iframe, whose document would otherwise swallow the release.\n// Synthetic events carry no active pointer, so a failed capture is fine.\nfunction capturePointer(event: ReactPointerEvent) {\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n // Not an active pointer; the document listeners still track the gesture.\n }\n}\n\n// Starts a drag from the title bar or a resize from an edge or corner. The\n// gesture itself is tracked on the document by useWindowPointerTracking.\nfunction useGestureStarts(\n windowRef: RefObject<HTMLElement | null>,\n maximized: boolean,\n position: WindowPosition | null,\n dragging: MutableRefObject<WindowDragState | null>,\n resizing: MutableRefObject<WindowResizeState | null>,\n) {\n const handlePointerDown = useCallback(\n (event: ReactPointerEvent) => {\n // One gesture at a time: a second pointer pressing the title bar or a\n // resize handle mid-gesture must not take it over.\n if (!position || maximized || dragging.current || resizing.current) {\n return;\n }\n dragging.current = {\n offsetX: event.clientX - position.x,\n offsetY: event.clientY - position.y,\n pointerId: event.pointerId,\n };\n capturePointer(event);\n },\n [dragging, maximized, position, resizing],\n );\n\n const handleResizePointerDown = useCallback(\n (event: ReactPointerEvent, edge: ResizeEdge) => {\n if (\n maximized ||\n !position ||\n !windowRef.current ||\n dragging.current ||\n resizing.current\n ) {\n return;\n }\n event.stopPropagation();\n capturePointer(event);\n const el = windowRef.current;\n const computed = getComputedStyle(el);\n const borderBox = computed.boxSizing === \"border-box\";\n resizing.current = {\n edge,\n pointerId: event.pointerId,\n startX: event.clientX,\n startY: event.clientY,\n startLeft: position.x,\n startTop: position.y,\n startWidth: parseFloat(computed.width),\n startHeight: parseFloat(computed.height),\n borderX: borderBox ? 0 : el.offsetWidth - el.clientWidth,\n borderY: borderBox ? 0 : el.offsetHeight - el.clientHeight,\n };\n },\n [maximized, position, resizing, windowRef],\n );\n\n return { handlePointerDown, handleResizePointerDown };\n}\n\nexport function useWindowGeometry(\n entry: WindowEntry,\n maximized: boolean,\n windowRef: RefObject<HTMLElement | null>,\n) {\n const { commit, live, position, setPosition, setSize, size } =\n useLiveGeometry(entry);\n const dragging = useRef<WindowDragState | null>(null);\n const resizing = useRef<WindowResizeState | null>(null);\n // Maximizing or minimizing mid-gesture (a second touch on the title bar's\n // controls) abandons the gesture: its frames were measured at the normal\n // size, so the live geometry goes back to the committed geometry.\n useEffect(() => {\n if (!(maximized || entry.minimized)) {\n return;\n }\n if (!dragging.current && !resizing.current) {\n return;\n }\n dragging.current = null;\n resizing.current = null;\n setSize(entry.size ?? null);\n if (entry.position) {\n setPosition(entry.position);\n }\n }, [\n entry.minimized,\n entry.position,\n entry.size,\n maximized,\n setPosition,\n setSize,\n ]);\n const clamp = useCallback(\n (x: number, y: number) =>\n clampWindowPosition(windowRef.current, x, y, live.current.size),\n [live, windowRef],\n );\n\n const { hold } = useWindowLayout({\n clamp,\n commit,\n dragging,\n entry,\n live,\n resizing,\n setPosition,\n size,\n windowRef,\n });\n\n // A finished gesture commits its geometry, then runs any layout it held\n // off (a surface resize mid-gesture), even when the geometry did not change.\n const finishGesture = useCallback(() => {\n commit();\n hold(false);\n }, [commit, hold]);\n\n useWindowPointerTracking(\n windowRef,\n dragging,\n resizing,\n clamp,\n setPosition,\n setSize,\n finishGesture,\n );\n\n const { handlePointerDown, handleResizePointerDown } = useGestureStarts(\n windowRef,\n maximized,\n position,\n dragging,\n resizing,\n );\n\n const stepped = useSteppedGeometry(\n windowRef,\n maximized,\n live,\n clamp,\n setPosition,\n setSize,\n );\n\n return {\n ...stepped,\n commit,\n hold,\n handlePointerDown,\n handleResizePointerDown,\n position,\n size,\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useWindowItemRegistration.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/useWindowItemRegistration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAqBzD,MAAM,UAAU,yBAAyB,CACvC,OAA6D;IAE7D,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,GACzE,OAAO,CAAC;IACV,MAAM,SAAS,GAAG,MAAM,CAA0B,IAAI,CAAC,CAAC;IACxD,MAAM,qBAAqB,GACzB,MAAM,CAAsD,IAAI,CAAC,CAAC;IACpE,MAAM,iBAAiB,GAAG,MAAM,CAAS,EAAE,CAAC,CAAC;IAE7C,eAAe,CAAC,GAAG,EAAE;QACnB,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAC7B,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAClE,MAAM,cAAc,GAClB,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAEpE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,OAAO,CAAC;QACzD,MAAM,UAAU,GAAG,kBAAkB,EAAE,IAAI,IAAI,IAAI,CAAC;QACpD,MAAM,WAAW,GACf,UAAU,KAAK,cAAc;YAC7B,CAAC,UAAU,KAAK,IAAI;gBAClB,cAAc,KAAK,IAAI;gBACvB,cAAc,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;QAChD,IACE,WAAW;YACX,kBAAkB,EAAE,YAAY,KAAK,YAAY;YACjD,kBAAkB,CAAC,cAAc,KAAK,cAAc,EACpD,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,cAAc,GAAG,iBAAiB,CAAC,OAAO,CAAC;QACjD,IAAI,kBAAkB,EAAE,IAAI,EAAE,CAAC;YAC7B,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,cAAc,EAAE,CAAC;YACnB,YAAY,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;QAC/C,CAAC;QACD,qBAAqB,CAAC,OAAO,GAAG;YAC9B,IAAI,EAAE,cAAc;YACpB,YAAY;YACZ,cAAc;SACf,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,SAAS,CACP,GAAG,EAAE,CAAC,GAAG,EAAE;QACT,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,OAAO,CAAC;QACzD,IAAI,kBAAkB,EAAE,IAAI,EAAE,CAAC;YAC7B,kBAAkB,CAAC,cAAc,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC/D,CAAC;QACD,qBAAqB,CAAC,OAAO,GAAG,IAAI,CAAC;IACvC,CAAC,EACD,EAAE,CACH,CAAC;AACJ,CAAC","sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useRef } from \"react\";\nimport { sameWindowItem } from \"./useWindowItemRegistry\";\n\ntype WindowItemAction = () => unknown;\n\ninterface WindowItemRegistrationOptions<Input, RegisteredItem extends object> {\n action: WindowItemAction | null;\n createRegisteredItem: (\n input: Input,\n handleAction: WindowItemAction,\n ) => RegisteredItem | null;\n input: Input | null;\n registerItem: (id: object, item: RegisteredItem) => void;\n unregisterItem: (id: object) => void;\n}\n\ninterface ActiveWindowItemRegistration<T extends object> {\n readonly item: T | null;\n readonly registerItem: (id: object, item: T) => void;\n readonly unregisterItem: (id: object) => void;\n}\n\nexport function useWindowItemRegistration<Input, RegisteredItem extends object>(\n options: WindowItemRegistrationOptions<Input, RegisteredItem>,\n): void {\n const { action, createRegisteredItem, input, registerItem, unregisterItem } =\n options;\n const actionRef = useRef<WindowItemAction | null>(null);\n const activeRegistrationRef =\n useRef<ActiveWindowItemRegistration<RegisteredItem> | null>(null);\n const registrationIdRef = useRef<object>({});\n\n useLayoutEffect(() => {\n actionRef.current = action;\n }, [action]);\n\n const handleAction = useCallback(() => actionRef.current?.(), []);\n const registeredItem =\n input === null ? null : createRegisteredItem(input, handleAction);\n\n useEffect(() => {\n const activeRegistration = activeRegistrationRef.current;\n const activeItem = activeRegistration?.item ?? null;\n const itemMatches =\n activeItem === registeredItem ||\n (activeItem !== null &&\n registeredItem !== null &&\n sameWindowItem(activeItem, registeredItem));\n if (\n itemMatches &&\n activeRegistration?.registerItem === registerItem &&\n activeRegistration.unregisterItem === unregisterItem\n ) {\n return;\n }\n\n const registrationId = registrationIdRef.current;\n if (activeRegistration?.item) {\n activeRegistration.unregisterItem(registrationId);\n }\n if (registeredItem) {\n registerItem(registrationId, registeredItem);\n }\n activeRegistrationRef.current = {\n item: registeredItem,\n registerItem,\n unregisterItem,\n };\n });\n\n useEffect(\n () => () => {\n const activeRegistration = activeRegistrationRef.current;\n if (activeRegistration?.item) {\n activeRegistration.unregisterItem(registrationIdRef.current);\n }\n activeRegistrationRef.current = null;\n },\n [],\n );\n}\n"]}
1
+ {"version":3,"file":"useWindowItemRegistration.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/useWindowItemRegistration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAqBzD,MAAM,UAAU,yBAAyB,CACvC,OAA6D;IAE7D,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,GACzE,OAAO,CAAC;IACV,MAAM,SAAS,GAAG,MAAM,CAA0B,IAAI,CAAC,CAAC;IACxD,MAAM,qBAAqB,GACzB,MAAM,CAAsD,IAAI,CAAC,CAAC;IACpE,MAAM,iBAAiB,GAAG,MAAM,CAAS,EAAE,CAAC,CAAC;IAE7C,eAAe,CAAC,GAAG,EAAE;QACnB,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAC7B,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAClE,MAAM,cAAc,GAClB,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAEpE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,OAAO,CAAC;QACzD,MAAM,UAAU,GAAG,kBAAkB,EAAE,IAAI,IAAI,IAAI,CAAC;QACpD,MAAM,WAAW,GACf,UAAU,KAAK,cAAc;YAC7B,CAAC,UAAU,KAAK,IAAI;gBAClB,cAAc,KAAK,IAAI;gBACvB,cAAc,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;QAChD,IACE,WAAW;YACX,kBAAkB,EAAE,YAAY,KAAK,YAAY;YACjD,kBAAkB,CAAC,cAAc,KAAK,cAAc,EACpD,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,cAAc,GAAG,iBAAiB,CAAC,OAAO,CAAC;QACjD,IAAI,kBAAkB,EAAE,IAAI,EAAE,CAAC;YAC7B,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,cAAc,EAAE,CAAC;YACnB,YAAY,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;QAC/C,CAAC;QACD,qBAAqB,CAAC,OAAO,GAAG;YAC9B,IAAI,EAAE,cAAc;YACpB,YAAY;YACZ,cAAc;SACf,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,SAAS,CACP,GAAG,EAAE,CAAC,GAAG,EAAE;QACT,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,OAAO,CAAC;QACzD,IAAI,kBAAkB,EAAE,IAAI,EAAE,CAAC;YAC7B,kBAAkB,CAAC,cAAc,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC/D,CAAC;QACD,qBAAqB,CAAC,OAAO,GAAG,IAAI,CAAC;IACvC,CAAC,EACD,EAAE,CACH,CAAC;AACJ,CAAC","sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useRef } from \"react\";\nimport { sameWindowItem } from \"./useWindowItemRegistry\";\n\ntype WindowItemAction = () => unknown;\n\ninterface WindowItemRegistrationOptions<Input, RegisteredItem extends object> {\n action: WindowItemAction | null;\n createRegisteredItem: (\n input: Input,\n handleAction: WindowItemAction,\n ) => RegisteredItem | null;\n input: Input | null;\n registerItem: (id: object, item: RegisteredItem) => void;\n unregisterItem: (id: object) => void;\n}\n\ninterface ActiveWindowItemRegistration<T extends object> {\n readonly item: T | null;\n readonly registerItem: (id: object, item: T) => void;\n readonly unregisterItem: (id: object) => void;\n}\n\nexport function useWindowItemRegistration<Input, RegisteredItem extends object>(\n options: WindowItemRegistrationOptions<Input, RegisteredItem>,\n): void {\n const { action, createRegisteredItem, input, registerItem, unregisterItem } =\n options;\n const actionRef = useRef<WindowItemAction | null>(null);\n const activeRegistrationRef =\n useRef<ActiveWindowItemRegistration<RegisteredItem> | null>(null);\n const registrationIdRef = useRef<object>({});\n\n useLayoutEffect(() => {\n actionRef.current = action;\n }, [action]);\n\n const handleAction = useCallback(() => actionRef.current?.(), []);\n const registeredItem =\n input === null ? null : createRegisteredItem(input, handleAction);\n\n useEffect(() => {\n const activeRegistration = activeRegistrationRef.current;\n const activeItem = activeRegistration?.item ?? null;\n const itemMatches =\n activeItem === registeredItem ||\n (activeItem !== null &&\n registeredItem !== null &&\n sameWindowItem(activeItem, registeredItem));\n if (\n itemMatches &&\n activeRegistration?.registerItem === registerItem &&\n activeRegistration.unregisterItem === unregisterItem\n ) {\n return;\n }\n\n const registrationId = registrationIdRef.current;\n if (activeRegistration?.item) {\n activeRegistration.unregisterItem(registrationId);\n }\n if (registeredItem) {\n registerItem(registrationId, registeredItem);\n }\n activeRegistrationRef.current = {\n item: registeredItem,\n registerItem,\n unregisterItem,\n };\n });\n\n useEffect(\n () => () => {\n const activeRegistration = activeRegistrationRef.current;\n if (activeRegistration?.item) {\n activeRegistration.unregisterItem(registrationIdRef.current);\n }\n activeRegistrationRef.current = null;\n },\n [],\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useWindowItemRegistry.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/useWindowItemRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAQvD,MAAM,UAAU,cAAc,CAC5B,IAAmB,EACnB,KAAQ;IAER,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3C,OAAO,CACL,WAAW,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM;QAC1C,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE,CAC5C,WAAW,CAAC,IAAI,CACd,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,CACvB,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,CAC3D,CACF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAoD;IAEpD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAyB,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAE5E,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,EAAU,EAAE,IAAO,EAAE,EAAE;QACtB,QAAQ,CAAC,CAAC,YAAY,EAAE,EAAE;YACxB,IAAI,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;gBACzC,OAAO,YAAY,CAAC;YACtB,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;YACxC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACxB,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,EAAU,EAAE,EAAE;QAChD,QAAQ,CAAC,CAAC,YAAY,EAAE,EAAE;YACxB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC1B,OAAO,YAAY,CAAC;YACtB,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;YACxC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACrB,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,OAAO,CACZ,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC,EAC/C,CAAC,KAAK,EAAE,YAAY,EAAE,cAAc,CAAC,CACtC,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,yBAAyB,CACvC,KAA6B;IAE7B,IAAI,QAAQ,GAAa,IAAI,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACnD,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\ninterface WindowItemRegistry<T> {\n items: ReadonlyMap<object, T>;\n registerItem: (id: object, item: T) => void;\n unregisterItem: (id: object) => void;\n}\n\nexport function sameWindowItem<T extends object>(\n left: T | undefined,\n right: T,\n): boolean {\n if (!left) {\n return false;\n }\n\n const leftEntries = Object.entries(left);\n const rightEntries = Object.entries(right);\n return (\n leftEntries.length === rightEntries.length &&\n rightEntries.every(([rightKey, rightValue]) =>\n leftEntries.some(\n ([leftKey, leftValue]) =>\n leftKey === rightKey && Object.is(leftValue, rightValue),\n ),\n )\n );\n}\n\nexport function useWindowItemRegistry<T>(\n sameItem: (left: T | undefined, right: T) => boolean,\n): WindowItemRegistry<T> {\n const [items, setItems] = useState<ReadonlyMap<object, T>>(() => new Map());\n\n const registerItem = useCallback(\n (id: object, item: T) => {\n setItems((currentItems) => {\n if (sameItem(currentItems.get(id), item)) {\n return currentItems;\n }\n\n const nextItems = new Map(currentItems);\n nextItems.set(id, item);\n return nextItems;\n });\n },\n [sameItem],\n );\n\n const unregisterItem = useCallback((id: object) => {\n setItems((currentItems) => {\n if (!currentItems.has(id)) {\n return currentItems;\n }\n\n const nextItems = new Map(currentItems);\n nextItems.delete(id);\n return nextItems;\n });\n }, []);\n\n return useMemo(\n () => ({ items, registerItem, unregisterItem }),\n [items, registerItem, unregisterItem],\n );\n}\n\n/** Highest priority wins among registered items; null when none registered. */\nexport function selectHighestPriorityItem<T extends { priority: number }>(\n items: ReadonlyMap<object, T>,\n): T | null {\n let selected: T | null = null;\n\n for (const item of items.values()) {\n if (!selected || item.priority > selected.priority) {\n selected = item;\n }\n }\n\n return selected;\n}\n"]}
1
+ {"version":3,"file":"useWindowItemRegistry.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/useWindowItemRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAQvD,MAAM,UAAU,cAAc,CAC5B,IAAmB,EACnB,KAAQ;IAER,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3C,OAAO,CACL,WAAW,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM;QAC1C,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE,CAC5C,WAAW,CAAC,IAAI,CACd,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,CACvB,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,CAC3D,CACF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAoD;IAEpD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAyB,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAE5E,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,EAAU,EAAE,IAAO,EAAE,EAAE;QACtB,QAAQ,CAAC,CAAC,YAAY,EAAE,EAAE;YACxB,IAAI,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;gBACzC,OAAO,YAAY,CAAC;YACtB,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;YACxC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACxB,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,EAAU,EAAE,EAAE;QAChD,QAAQ,CAAC,CAAC,YAAY,EAAE,EAAE;YACxB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC1B,OAAO,YAAY,CAAC;YACtB,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;YACxC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACrB,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,OAAO,CACZ,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC,EAC/C,CAAC,KAAK,EAAE,YAAY,EAAE,cAAc,CAAC,CACtC,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,yBAAyB,CACvC,KAA6B;IAE7B,IAAI,QAAQ,GAAa,IAAI,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACnD,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\ninterface WindowItemRegistry<T> {\n items: ReadonlyMap<object, T>;\n registerItem: (id: object, item: T) => void;\n unregisterItem: (id: object) => void;\n}\n\nexport function sameWindowItem<T extends object>(\n left: T | undefined,\n right: T,\n): boolean {\n if (!left) {\n return false;\n }\n\n const leftEntries = Object.entries(left);\n const rightEntries = Object.entries(right);\n return (\n leftEntries.length === rightEntries.length &&\n rightEntries.every(([rightKey, rightValue]) =>\n leftEntries.some(\n ([leftKey, leftValue]) =>\n leftKey === rightKey && Object.is(leftValue, rightValue),\n ),\n )\n );\n}\n\nexport function useWindowItemRegistry<T>(\n sameItem: (left: T | undefined, right: T) => boolean,\n): WindowItemRegistry<T> {\n const [items, setItems] = useState<ReadonlyMap<object, T>>(() => new Map());\n\n const registerItem = useCallback(\n (id: object, item: T) => {\n setItems((currentItems) => {\n if (sameItem(currentItems.get(id), item)) {\n return currentItems;\n }\n\n const nextItems = new Map(currentItems);\n nextItems.set(id, item);\n return nextItems;\n });\n },\n [sameItem],\n );\n\n const unregisterItem = useCallback((id: object) => {\n setItems((currentItems) => {\n if (!currentItems.has(id)) {\n return currentItems;\n }\n\n const nextItems = new Map(currentItems);\n nextItems.delete(id);\n return nextItems;\n });\n }, []);\n\n return useMemo(\n () => ({ items, registerItem, unregisterItem }),\n [items, registerItem, unregisterItem],\n );\n}\n\n/** Highest priority wins among registered items; null when none registered. */\nexport function selectHighestPriorityItem<T extends { priority: number }>(\n items: ReadonlyMap<object, T>,\n): T | null {\n let selected: T | null = null;\n\n for (const item of items.values()) {\n if (!selected || item.priority > selected.priority) {\n selected = item;\n }\n }\n\n return selected;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useWindowKeyboardGeometry.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/useWindowKeyboardGeometry.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type RefObject,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { WindowMenuItem } from \"./WindowMenuBar\";\nimport type { LiveGeometry } from \"./windowGeometry\";\n\ntype WindowKeyboardMode = \"move\" | \"resize\";\n\nconst STEP_PX = 10;\n\nconst ARROW_DIRECTIONS: Readonly<Record<string, readonly [number, number]>> = {\n ArrowDown: [0, 1],\n ArrowLeft: [-1, 0],\n ArrowRight: [1, 0],\n ArrowUp: [0, -1],\n};\n\nconst MODE_HINTS: Readonly<Record<WindowKeyboardMode, string>> = {\n move: \"Moving window: arrow keys move it, Enter keeps it, Escape cancels.\",\n resize:\n \"Resizing window: arrow keys resize it, Enter keeps it, Escape cancels.\",\n};\n\ninterface KeyboardGeometryHost {\n available: boolean;\n windowRef: RefObject<HTMLElement | null>;\n}\n\ninterface SteppedGeometry {\n commit: () => void;\n grow: (deltaWidth: number, deltaHeight: number) => void;\n // Holds the window's layout while the mode owns its geometry.\n hold: (holding: boolean) => void;\n nudge: (deltaX: number, deltaY: number) => void;\n restore: (saved: LiveGeometry) => void;\n snapshot: () => LiveGeometry;\n}\n\n// Keyboard move and resize, entered from the window's View menu the way a\n// desktop system menu offers them. Arrow keys step the window, Enter keeps the\n// result, and Escape puts it back. Keys are captured only while a mode is\n// active, so no shortcut competes with text editing inside the window. The\n// mode focuses its window and ends, keeping the result, as soon as focus moves\n// off the window itself (to a control inside it or anything else) or a pointer\n// presses anywhere; minimizing or maximizing the window cancels it, so its key\n// capture never outlives the window it moves.\nfunction useWindowKeyboardGeometry(\n { commit, grow, hold, nudge, restore, snapshot }: SteppedGeometry,\n { available, windowRef }: KeyboardGeometryHost,\n announce: (message: string) => void,\n) {\n const [mode, setMode] = useState<WindowKeyboardMode | null>(null);\n const startGeometry = useRef<LiveGeometry | null>(null);\n\n const startKeyboardMode = useCallback(\n (nextMode: WindowKeyboardMode) => {\n startGeometry.current = snapshot();\n hold(true);\n setMode(nextMode);\n announce(MODE_HINTS[nextMode]);\n windowRef.current?.focus({ preventScroll: true });\n },\n [announce, hold, snapshot, windowRef],\n );\n\n useEffect(() => {\n if (available || !mode) {\n return;\n }\n if (startGeometry.current) {\n restore(startGeometry.current);\n }\n hold(false);\n setMode(null);\n }, [available, hold, mode, restore]);\n\n useEffect(() => {\n if (!mode) {\n return;\n }\n\n function leave() {\n commit();\n hold(false);\n setMode(null);\n }\n\n function handleFocusIn(event: FocusEvent) {\n if (event.target !== windowRef.current) {\n leave();\n }\n }\n\n function finish(event: KeyboardEvent, keep: boolean) {\n event.preventDefault();\n event.stopPropagation();\n if (keep) {\n commit();\n } else if (startGeometry.current) {\n restore(startGeometry.current);\n }\n hold(false);\n setMode(null);\n }\n\n function handleKeyDown(event: KeyboardEvent) {\n const direction = ARROW_DIRECTIONS[event.key];\n if (direction) {\n event.preventDefault();\n event.stopPropagation();\n const [x, y] = direction;\n if (mode === \"move\") {\n nudge(x * STEP_PX, y * STEP_PX);\n } else {\n grow(x * STEP_PX, y * STEP_PX);\n }\n return;\n }\n if (event.key === \"Enter\") {\n finish(event, true);\n } else if (event.key === \"Escape\") {\n finish(event, false);\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown, true);\n document.addEventListener(\"pointerdown\", leave, true);\n document.addEventListener(\"focusin\", handleFocusIn, true);\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown, true);\n document.removeEventListener(\"pointerdown\", leave, true);\n document.removeEventListener(\"focusin\", handleFocusIn, true);\n };\n }, [commit, grow, hold, mode, nudge, restore, windowRef]);\n\n return startKeyboardMode;\n}\n\n// The View menu entries that start keyboard move and resize.\nexport function useWindowGeometryMenuItems(\n stepped: SteppedGeometry,\n {\n maximized,\n minimized,\n windowRef,\n }: {\n maximized: boolean;\n minimized: boolean;\n windowRef: RefObject<HTMLElement | null>;\n },\n announce: (message: string) => void,\n): WindowMenuItem[] {\n const startKeyboardMode = useWindowKeyboardGeometry(\n stepped,\n { available: !maximized && !minimized, windowRef },\n announce,\n );\n return useMemo(\n () => [\n {\n disabled: maximized,\n id: \"keyboard-move\",\n label: \"Move Window\",\n onClick: () => startKeyboardMode(\"move\"),\n },\n {\n disabled: maximized,\n id: \"keyboard-resize\",\n label: \"Resize Window\",\n onClick: () => startKeyboardMode(\"resize\"),\n },\n ],\n [maximized, startKeyboardMode],\n );\n}\n\n// Moves focus into a window when it opens or comes back from minimized, unless\n// focus is already inside it, such as an autofocused field. `shown` must only\n// turn true once the window is laid out and visible: browsers ignore focus on\n// an element that is still `visibility: hidden`. Only the foremost window takes\n// focus, so windows remounting together leave it on the front one.\nexport function useFocusWindowOnShow(\n windowRef: RefObject<HTMLElement | null>,\n { isTop, shown }: { isTop: boolean; shown: boolean },\n) {\n const hidden = useRef(true);\n\n useEffect(() => {\n if (!shown) {\n hidden.current = true;\n return;\n }\n if (!hidden.current) {\n return;\n }\n hidden.current = false;\n const root = windowRef.current;\n if (isTop && root && !root.contains(document.activeElement)) {\n root.focus({ preventScroll: true });\n }\n }, [isTop, shown, windowRef]);\n}\n"]}
1
+ {"version":3,"file":"useWindowKeyboardGeometry.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/useWindowKeyboardGeometry.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type RefObject,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { WindowMenuItem } from \"./WindowMenuBar\";\nimport type { LiveGeometry } from \"./windowGeometry\";\n\ntype WindowKeyboardMode = \"move\" | \"resize\";\n\nconst STEP_PX = 10;\n\nconst ARROW_DIRECTIONS: Readonly<Record<string, readonly [number, number]>> = {\n ArrowDown: [0, 1],\n ArrowLeft: [-1, 0],\n ArrowRight: [1, 0],\n ArrowUp: [0, -1],\n};\n\nconst MODE_HINTS: Readonly<Record<WindowKeyboardMode, string>> = {\n move: \"Moving window: arrow keys move it, Enter keeps it, Escape cancels.\",\n resize:\n \"Resizing window: arrow keys resize it, Enter keeps it, Escape cancels.\",\n};\n\ninterface KeyboardGeometryHost {\n available: boolean;\n windowRef: RefObject<HTMLElement | null>;\n}\n\ninterface SteppedGeometry {\n commit: () => void;\n grow: (deltaWidth: number, deltaHeight: number) => void;\n // Holds the window's layout while the mode owns its geometry.\n hold: (holding: boolean) => void;\n nudge: (deltaX: number, deltaY: number) => void;\n restore: (saved: LiveGeometry) => void;\n snapshot: () => LiveGeometry;\n}\n\n// Keyboard move and resize, entered from the window's View menu the way a\n// desktop system menu offers them. Arrow keys step the window, Enter keeps the\n// result, and Escape puts it back. Keys are captured only while a mode is\n// active, so no shortcut competes with text editing inside the window. The\n// mode focuses its window and ends, keeping the result, as soon as focus moves\n// off the window itself (to a control inside it or anything else) or a pointer\n// presses anywhere; minimizing or maximizing the window cancels it, so its key\n// capture never outlives the window it moves.\nfunction useWindowKeyboardGeometry(\n { commit, grow, hold, nudge, restore, snapshot }: SteppedGeometry,\n { available, windowRef }: KeyboardGeometryHost,\n announce: (message: string) => void,\n) {\n const [mode, setMode] = useState<WindowKeyboardMode | null>(null);\n const startGeometry = useRef<LiveGeometry | null>(null);\n\n const startKeyboardMode = useCallback(\n (nextMode: WindowKeyboardMode) => {\n startGeometry.current = snapshot();\n hold(true);\n setMode(nextMode);\n announce(MODE_HINTS[nextMode]);\n windowRef.current?.focus({ preventScroll: true });\n },\n [announce, hold, snapshot, windowRef],\n );\n\n useEffect(() => {\n if (available || !mode) {\n return;\n }\n if (startGeometry.current) {\n restore(startGeometry.current);\n }\n hold(false);\n setMode(null);\n }, [available, hold, mode, restore]);\n\n useEffect(() => {\n if (!mode) {\n return;\n }\n\n function leave() {\n commit();\n hold(false);\n setMode(null);\n }\n\n function handleFocusIn(event: FocusEvent) {\n if (event.target !== windowRef.current) {\n leave();\n }\n }\n\n function finish(event: KeyboardEvent, keep: boolean) {\n event.preventDefault();\n event.stopPropagation();\n if (keep) {\n commit();\n } else if (startGeometry.current) {\n restore(startGeometry.current);\n }\n hold(false);\n setMode(null);\n }\n\n function handleKeyDown(event: KeyboardEvent) {\n const direction = ARROW_DIRECTIONS[event.key];\n if (direction) {\n event.preventDefault();\n event.stopPropagation();\n const [x, y] = direction;\n if (mode === \"move\") {\n nudge(x * STEP_PX, y * STEP_PX);\n } else {\n grow(x * STEP_PX, y * STEP_PX);\n }\n return;\n }\n if (event.key === \"Enter\") {\n finish(event, true);\n } else if (event.key === \"Escape\") {\n finish(event, false);\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown, true);\n document.addEventListener(\"pointerdown\", leave, true);\n document.addEventListener(\"focusin\", handleFocusIn, true);\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown, true);\n document.removeEventListener(\"pointerdown\", leave, true);\n document.removeEventListener(\"focusin\", handleFocusIn, true);\n };\n }, [commit, grow, hold, mode, nudge, restore, windowRef]);\n\n return startKeyboardMode;\n}\n\n// The View menu entries that start keyboard move and resize.\nexport function useWindowGeometryMenuItems(\n stepped: SteppedGeometry,\n {\n maximized,\n minimized,\n windowRef,\n }: {\n maximized: boolean;\n minimized: boolean;\n windowRef: RefObject<HTMLElement | null>;\n },\n announce: (message: string) => void,\n): WindowMenuItem[] {\n const startKeyboardMode = useWindowKeyboardGeometry(\n stepped,\n { available: !maximized && !minimized, windowRef },\n announce,\n );\n return useMemo(\n () => [\n {\n disabled: maximized,\n id: \"keyboard-move\",\n label: \"Move Window\",\n onClick: () => startKeyboardMode(\"move\"),\n },\n {\n disabled: maximized,\n id: \"keyboard-resize\",\n label: \"Resize Window\",\n onClick: () => startKeyboardMode(\"resize\"),\n },\n ],\n [maximized, startKeyboardMode],\n );\n}\n\n// Moves focus into a window when it opens or comes back from minimized, unless\n// focus is already inside it, such as an autofocused field. `shown` must only\n// turn true once the window is laid out and visible: browsers ignore focus on\n// an element that is still `visibility: hidden`. Only the foremost window takes\n// focus, so windows remounting together leave it on the front one.\nexport function useFocusWindowOnShow(\n windowRef: RefObject<HTMLElement | null>,\n { isTop, shown }: { isTop: boolean; shown: boolean },\n) {\n const hidden = useRef(true);\n\n useEffect(() => {\n if (!shown) {\n hidden.current = true;\n return;\n }\n if (!hidden.current) {\n return;\n }\n hidden.current = false;\n const root = windowRef.current;\n if (isTop && root && !root.contains(document.activeElement)) {\n root.focus({ preventScroll: true });\n }\n }, [isTop, shown, windowRef]);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useWindowLayout.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/useWindowLayout.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type MutableRefObject,\n type RefObject,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport type {\n WindowEntry,\n WindowPosition,\n WindowSize,\n} from \"./WindowStateProvider\";\nimport {\n clampWindowPosition,\n type LiveGeometry,\n type WindowDragState,\n type WindowResizeState,\n} from \"./windowGeometry\";\n\ninterface WindowLayoutInput {\n clamp: (x: number, y: number) => WindowPosition;\n commit: () => void;\n dragging: MutableRefObject<WindowDragState | null>;\n entry: WindowEntry;\n live: MutableRefObject<LiveGeometry>;\n resizing: MutableRefObject<WindowResizeState | null>;\n setPosition: (value: WindowPosition) => void;\n size: WindowSize | null;\n windowRef: RefObject<HTMLElement | null>;\n}\n\n// A gesture (a pointer drag or resize, or a keyboard move or resize) owns the\n// live geometry until it ends: layout holds off meanwhile, so it never commits\n// an unconfirmed frame, and runs once when the gesture lets go.\nfunction useGestureHold(\n dragging: MutableRefObject<WindowDragState | null>,\n resizing: MutableRefObject<WindowResizeState | null>,\n) {\n const held = useRef(false);\n const deferred = useRef(false);\n const isBusy = useCallback(\n () =>\n held.current || dragging.current !== null || resizing.current !== null,\n [dragging, resizing],\n );\n return { deferred, held, isBusy };\n}\n\n// A surface with no size is hidden (display: none), so nothing measured\n// against it is meaningful.\nfunction isUnsized(container: HTMLElement) {\n return container.clientWidth === 0 && container.clientHeight === 0;\n}\n\n// The surface changing size (a workspace shown after being hidden, a resized\n// viewport) lays the window out again.\nfunction useSurfaceObserver(\n windowRef: RefObject<HTMLElement | null>,\n minimized: boolean,\n layout: () => void,\n) {\n useEffect(() => {\n const container = windowRef.current?.parentElement;\n if (minimized || !container || typeof ResizeObserver === \"undefined\") {\n return;\n }\n const observer = new ResizeObserver(() => layout());\n observer.observe(container);\n return () => observer.disconnect();\n }, [layout, minimized, windowRef]);\n}\n\nexport function useWindowLayout({\n clamp,\n commit,\n dragging,\n entry,\n live,\n resizing,\n setPosition,\n size,\n windowRef,\n}: WindowLayoutInput) {\n // Lay the window out from its committed position, or from its viewport\n // starting point the first time, and commit where it actually landed. A\n // minimized window has no element to measure and a maximized one measures at\n // full size, so this waits both out. A hidden surface (an inactive\n // workspace) measures at zero: the window takes its intended position\n // unclamped and nothing is committed until the surface has a size.\n const { deferred, held, isBusy } = useGestureHold(dragging, resizing);\n // `release` lays out from the live geometry a gesture just finished with,\n // which the committed position does not reflect until it re-renders.\n const layout = useCallback(\n (release = false) => {\n const element = windowRef.current;\n const container = element?.parentElement;\n if (entry.minimized || entry.maximized || !element || !container) {\n return;\n }\n if (isBusy()) {\n deferred.current = true;\n return;\n }\n if (!live.current.size) {\n // A cleared size has not re-rendered yet; drop the old inline size so the\n // window measures at the stylesheet default it is about to take.\n element.style.removeProperty(\"width\");\n element.style.removeProperty(\"height\");\n }\n const containerRect = container.getBoundingClientRect();\n const start = (release ? live.current.position : null) ??\n entry.position ?? {\n x: entry.initialX - containerRect.left,\n y: entry.initialY - containerRect.top,\n };\n if (isUnsized(container)) {\n setPosition(start);\n return;\n }\n setPosition(clamp(start.x, start.y));\n commit();\n },\n [\n clamp,\n commit,\n deferred,\n entry.initialX,\n entry.initialY,\n entry.maximized,\n entry.minimized,\n entry.position,\n isBusy,\n live,\n setPosition,\n windowRef,\n ],\n );\n\n useEffect(() => {\n layout();\n }, [layout]);\n\n useSurfaceObserver(windowRef, entry.minimized, layout);\n\n // Once the window renders at a new size, including a cleared size falling\n // back to its stylesheet default, keep it inside the surface.\n useEffect(() => {\n const current = live.current.position;\n const container = windowRef.current?.parentElement;\n if (\n !current ||\n entry.maximized ||\n isBusy() ||\n !container ||\n isUnsized(container)\n ) {\n return;\n }\n const clamped = clampWindowPosition(\n windowRef.current,\n current.x,\n current.y,\n size,\n );\n if (clamped.x !== current.x || clamped.y !== current.y) {\n setPosition(clamped);\n commit();\n }\n }, [commit, entry.maximized, isBusy, live, setPosition, size, windowRef]);\n\n // Holds layout for a keyboard gesture; releasing it runs any layout the\n // gesture deferred.\n const hold = useCallback(\n (holding: boolean) => {\n held.current = holding;\n if (!holding && deferred.current) {\n deferred.current = false;\n layout(true);\n }\n },\n [deferred, held, layout],\n );\n\n return { hold };\n}\n"]}
1
+ {"version":3,"file":"useWindowLayout.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/useWindowLayout.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type MutableRefObject,\n type RefObject,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport type {\n WindowEntry,\n WindowPosition,\n WindowSize,\n} from \"./WindowStateProvider\";\nimport {\n clampWindowPosition,\n type LiveGeometry,\n type WindowDragState,\n type WindowResizeState,\n} from \"./windowGeometry\";\n\ninterface WindowLayoutInput {\n clamp: (x: number, y: number) => WindowPosition;\n commit: () => void;\n dragging: MutableRefObject<WindowDragState | null>;\n entry: WindowEntry;\n live: MutableRefObject<LiveGeometry>;\n resizing: MutableRefObject<WindowResizeState | null>;\n setPosition: (value: WindowPosition) => void;\n size: WindowSize | null;\n windowRef: RefObject<HTMLElement | null>;\n}\n\n// A gesture (a pointer drag or resize, or a keyboard move or resize) owns the\n// live geometry until it ends: layout holds off meanwhile, so it never commits\n// an unconfirmed frame, and runs once when the gesture lets go.\nfunction useGestureHold(\n dragging: MutableRefObject<WindowDragState | null>,\n resizing: MutableRefObject<WindowResizeState | null>,\n) {\n const held = useRef(false);\n const deferred = useRef(false);\n const isBusy = useCallback(\n () =>\n held.current || dragging.current !== null || resizing.current !== null,\n [dragging, resizing],\n );\n return { deferred, held, isBusy };\n}\n\n// A surface with no size is hidden (display: none), so nothing measured\n// against it is meaningful.\nfunction isUnsized(container: HTMLElement) {\n return container.clientWidth === 0 && container.clientHeight === 0;\n}\n\n// The surface changing size (a workspace shown after being hidden, a resized\n// viewport) lays the window out again.\nfunction useSurfaceObserver(\n windowRef: RefObject<HTMLElement | null>,\n minimized: boolean,\n layout: () => void,\n) {\n useEffect(() => {\n const container = windowRef.current?.parentElement;\n if (minimized || !container || typeof ResizeObserver === \"undefined\") {\n return;\n }\n const observer = new ResizeObserver(() => layout());\n observer.observe(container);\n return () => observer.disconnect();\n }, [layout, minimized, windowRef]);\n}\n\nexport function useWindowLayout({\n clamp,\n commit,\n dragging,\n entry,\n live,\n resizing,\n setPosition,\n size,\n windowRef,\n}: WindowLayoutInput) {\n // Lay the window out from its committed position, or from its viewport\n // starting point the first time, and commit where it actually landed. A\n // minimized window has no element to measure and a maximized one measures at\n // full size, so this waits both out. A hidden surface (an inactive\n // workspace) measures at zero: the window takes its intended position\n // unclamped and nothing is committed until the surface has a size.\n const { deferred, held, isBusy } = useGestureHold(dragging, resizing);\n // `release` lays out from the live geometry a gesture just finished with,\n // which the committed position does not reflect until it re-renders.\n const layout = useCallback(\n (release = false) => {\n const element = windowRef.current;\n const container = element?.parentElement;\n if (entry.minimized || entry.maximized || !element || !container) {\n return;\n }\n if (isBusy()) {\n deferred.current = true;\n return;\n }\n if (!live.current.size) {\n // A cleared size has not re-rendered yet; drop the old inline size so the\n // window measures at the stylesheet default it is about to take.\n element.style.removeProperty(\"width\");\n element.style.removeProperty(\"height\");\n }\n const containerRect = container.getBoundingClientRect();\n const start = (release ? live.current.position : null) ??\n entry.position ?? {\n x: entry.initialX - containerRect.left,\n y: entry.initialY - containerRect.top,\n };\n if (isUnsized(container)) {\n setPosition(start);\n return;\n }\n setPosition(clamp(start.x, start.y));\n commit();\n },\n [\n clamp,\n commit,\n deferred,\n entry.initialX,\n entry.initialY,\n entry.maximized,\n entry.minimized,\n entry.position,\n isBusy,\n live,\n setPosition,\n windowRef,\n ],\n );\n\n useEffect(() => {\n layout();\n }, [layout]);\n\n useSurfaceObserver(windowRef, entry.minimized, layout);\n\n // Once the window renders at a new size, including a cleared size falling\n // back to its stylesheet default, keep it inside the surface.\n useEffect(() => {\n const current = live.current.position;\n const container = windowRef.current?.parentElement;\n if (\n !current ||\n entry.maximized ||\n isBusy() ||\n !container ||\n isUnsized(container)\n ) {\n return;\n }\n const clamped = clampWindowPosition(\n windowRef.current,\n current.x,\n current.y,\n size,\n );\n if (clamped.x !== current.x || clamped.y !== current.y) {\n setPosition(clamped);\n commit();\n }\n }, [commit, entry.maximized, isBusy, live, setPosition, size, windowRef]);\n\n // Holds layout for a keyboard gesture; releasing it runs any layout the\n // gesture deferred.\n const hold = useCallback(\n (holding: boolean) => {\n held.current = holding;\n if (!holding && deferred.current) {\n deferred.current = false;\n layout(true);\n }\n },\n [deferred, held, layout],\n );\n\n return { hold };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useWindowToolbarReservationRegistry.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/useWindowToolbarReservationRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAShE,4EAA4E;AAC5E,6EAA6E;AAC7E,SAAS,sBAAsB,CAC7B,IAAyB,EACzB,KAAc;IAEd,OAAO,IAAI,KAAK,KAAK,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,mCAAmC;IACjD,MAAM,WAAW,GAAG,qBAAqB,CAAU,sBAAsB,CAAC,CAAC;IAC3E,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;IAEzD,OAAO,OAAO,CACZ,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE,WAAW,CAAC,YAAY;QAClC,QAAQ;QACR,QAAQ;QACR,UAAU,EAAE,WAAW,CAAC,cAAc;KACvC,CAAC,EACF,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,YAAY,EAAE,WAAW,CAAC,cAAc,CAAC,CAC3E,CAAC;AACJ,CAAC","sourcesContent":["import { useMemo } from \"react\";\nimport { useWindowItemRegistry } from \"./useWindowItemRegistry\";\n\ninterface WindowToolbarReservationRegistry {\n register: (id: object, reserved: boolean) => void;\n released: boolean;\n reserved: boolean;\n unregister: (id: object) => void;\n}\n\n// Module scope on purpose: the registry keys its callback identities on the\n// comparator, so an inline closure here re-registers every render and loops.\nfunction sameToolbarReservation(\n left: boolean | undefined,\n right: boolean,\n): boolean {\n return left === right;\n}\n\nexport function useWindowToolbarReservationRegistry(): WindowToolbarReservationRegistry {\n const reservation = useWindowItemRegistry<boolean>(sameToolbarReservation);\n const reserved = Array.from(reservation.items.values()).some(Boolean);\n const released = reservation.items.size > 0 && !reserved;\n\n return useMemo(\n () => ({\n register: reservation.registerItem,\n released,\n reserved,\n unregister: reservation.unregisterItem,\n }),\n [released, reserved, reservation.registerItem, reservation.unregisterItem],\n );\n}\n"]}
1
+ {"version":3,"file":"useWindowToolbarReservationRegistry.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/useWindowToolbarReservationRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAShE,4EAA4E;AAC5E,6EAA6E;AAC7E,SAAS,sBAAsB,CAC7B,IAAyB,EACzB,KAAc;IAEd,OAAO,IAAI,KAAK,KAAK,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,mCAAmC;IACjD,MAAM,WAAW,GAAG,qBAAqB,CAAU,sBAAsB,CAAC,CAAC;IAC3E,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;IAEzD,OAAO,OAAO,CACZ,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE,WAAW,CAAC,YAAY;QAClC,QAAQ;QACR,QAAQ;QACR,UAAU,EAAE,WAAW,CAAC,cAAc;KACvC,CAAC,EACF,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,YAAY,EAAE,WAAW,CAAC,cAAc,CAAC,CAC3E,CAAC;AACJ,CAAC","sourcesContent":["import { useMemo } from \"react\";\nimport { useWindowItemRegistry } from \"./useWindowItemRegistry\";\n\ninterface WindowToolbarReservationRegistry {\n register: (id: object, reserved: boolean) => void;\n released: boolean;\n reserved: boolean;\n unregister: (id: object) => void;\n}\n\n// Module scope on purpose: the registry keys its callback identities on the\n// comparator, so an inline closure here re-registers every render and loops.\nfunction sameToolbarReservation(\n left: boolean | undefined,\n right: boolean,\n): boolean {\n return left === right;\n}\n\nexport function useWindowToolbarReservationRegistry(): WindowToolbarReservationRegistry {\n const reservation = useWindowItemRegistry<boolean>(sameToolbarReservation);\n const reserved = Array.from(reservation.items.values()).some(Boolean);\n const released = reservation.items.size > 0 && !reserved;\n\n return useMemo(\n () => ({\n register: reservation.registerItem,\n released,\n reserved,\n unregister: reservation.unregisterItem,\n }),\n [released, reserved, reservation.registerItem, reservation.unregisterItem],\n );\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { ResizeCorner } from "./WindowResizeHandle.js";
1
+ import type { ResizeEdge } from "./WindowResizeHandle.js";
2
2
  import type { WindowPosition, WindowSize } from "./WindowStateProvider/index.js";
3
3
  export declare const MIN_WIDTH = 200;
4
4
  export declare const MIN_HEIGHT = 100;
@@ -8,7 +8,7 @@ export interface WindowDragState {
8
8
  pointerId: number;
9
9
  }
10
10
  export interface WindowResizeState {
11
- corner: ResizeCorner;
11
+ edge: ResizeEdge;
12
12
  pointerId: number;
13
13
  startHeight: number;
14
14
  startLeft: number;
@@ -22,10 +22,14 @@ export function clampWindowPosition(element, x, y, size) {
22
22
  export function resizeWindowWithinContainer(resizeState, clientX, clientY, container) {
23
23
  const deltaX = clientX - resizeState.startX;
24
24
  const deltaY = clientY - resizeState.startY;
25
- const movesLeft = resizeState.corner.includes("w");
26
- const movesUp = resizeState.corner.includes("n");
27
- let width = Math.max(MIN_WIDTH, resizeState.startWidth + deltaX * (movesLeft ? -1 : 1));
28
- let height = Math.max(MIN_HEIGHT, resizeState.startHeight + deltaY * (movesUp ? -1 : 1));
25
+ const { edge } = resizeState;
26
+ const movesLeft = edge.includes("w");
27
+ const movesUp = edge.includes("n");
28
+ // A side handle drags one edge, so the other axis keeps its start size.
29
+ const resizesX = movesLeft || edge.includes("e");
30
+ const resizesY = movesUp || edge.includes("s");
31
+ let width = Math.max(MIN_WIDTH, resizeState.startWidth + (resizesX ? deltaX * (movesLeft ? -1 : 1) : 0));
32
+ let height = Math.max(MIN_HEIGHT, resizeState.startHeight + (resizesY ? deltaY * (movesUp ? -1 : 1) : 0));
29
33
  let x = movesLeft
30
34
  ? resizeState.startLeft + resizeState.startWidth - width
31
35
  : resizeState.startLeft;
@@ -1 +1 @@
1
- {"version":3,"file":"windowGeometry.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/packages/windowing/src/window/windowGeometry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ResizeCorner } from \"./WindowResizeHandle\";\nimport type { WindowPosition, WindowSize } from \"./WindowStateProvider\";\n\n// Window geometry math shared by the pointer, keyboard, and layout hooks. All\n// positions and sizes are relative to the desktop surface.\n\nexport const MIN_WIDTH = 200;\nexport const MIN_HEIGHT = 100;\n\nexport interface WindowDragState {\n offsetX: number;\n offsetY: number;\n pointerId: number;\n}\n\nexport interface WindowResizeState {\n corner: ResizeCorner;\n pointerId: number;\n startHeight: number;\n startLeft: number;\n startTop: number;\n startWidth: number;\n startX: number;\n startY: number;\n borderX: number;\n borderY: number;\n}\n\nexport interface LiveGeometry {\n position: WindowPosition | null;\n size: WindowSize | null;\n}\n\n// Clamps against the size the window is about to render at when it is known,\n// so a position committed with a new size is not measured at the old one.\nexport function clampWindowPosition(\n element: HTMLElement | null,\n x: number,\n y: number,\n size: WindowSize | null,\n): WindowPosition {\n const container = element?.parentElement;\n if (!element || !container) {\n return { x, y };\n }\n // A requested size renders no smaller than the stylesheet's minimums.\n const width = size ? Math.max(MIN_WIDTH, size.width) : element.offsetWidth;\n const height = size\n ? Math.max(MIN_HEIGHT, size.height)\n : element.offsetHeight;\n\n return {\n x: Math.max(0, Math.min(x, container.clientWidth - width)),\n y: Math.max(0, Math.min(y, container.clientHeight - height)),\n };\n}\n\nexport function resizeWindowWithinContainer(\n resizeState: WindowResizeState,\n clientX: number,\n clientY: number,\n container: HTMLElement | null,\n) {\n const deltaX = clientX - resizeState.startX;\n const deltaY = clientY - resizeState.startY;\n const movesLeft = resizeState.corner.includes(\"w\");\n const movesUp = resizeState.corner.includes(\"n\");\n let width = Math.max(\n MIN_WIDTH,\n resizeState.startWidth + deltaX * (movesLeft ? -1 : 1),\n );\n let height = Math.max(\n MIN_HEIGHT,\n resizeState.startHeight + deltaY * (movesUp ? -1 : 1),\n );\n let x = movesLeft\n ? resizeState.startLeft + resizeState.startWidth - width\n : resizeState.startLeft;\n let y = movesUp\n ? resizeState.startTop + resizeState.startHeight - height\n : resizeState.startTop;\n\n if (container) {\n if (x < 0) {\n width += x;\n x = 0;\n }\n if (y < 0) {\n height += y;\n y = 0;\n }\n width = Math.min(width, container.clientWidth - x - resizeState.borderX);\n height = Math.min(height, container.clientHeight - y - resizeState.borderY);\n width = Math.max(MIN_WIDTH, width);\n height = Math.max(MIN_HEIGHT, height);\n }\n\n return {\n position: { x, y },\n size: { width, height },\n };\n}\n"]}
1
+ {"version":3,"file":"windowGeometry.js","sourceRoot":"","sources":["../../../home/a2f0/github/tearleads/packages/windowing/src/window/windowGeometry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ResizeEdge } from \"./WindowResizeHandle\";\nimport type { WindowPosition, WindowSize } from \"./WindowStateProvider\";\n\n// Window geometry math shared by the pointer, keyboard, and layout hooks. All\n// positions and sizes are relative to the desktop surface.\n\nexport const MIN_WIDTH = 200;\nexport const MIN_HEIGHT = 100;\n\nexport interface WindowDragState {\n offsetX: number;\n offsetY: number;\n pointerId: number;\n}\n\nexport interface WindowResizeState {\n edge: ResizeEdge;\n pointerId: number;\n startHeight: number;\n startLeft: number;\n startTop: number;\n startWidth: number;\n startX: number;\n startY: number;\n borderX: number;\n borderY: number;\n}\n\nexport interface LiveGeometry {\n position: WindowPosition | null;\n size: WindowSize | null;\n}\n\n// Clamps against the size the window is about to render at when it is known,\n// so a position committed with a new size is not measured at the old one.\nexport function clampWindowPosition(\n element: HTMLElement | null,\n x: number,\n y: number,\n size: WindowSize | null,\n): WindowPosition {\n const container = element?.parentElement;\n if (!element || !container) {\n return { x, y };\n }\n // A requested size renders no smaller than the stylesheet's minimums.\n const width = size ? Math.max(MIN_WIDTH, size.width) : element.offsetWidth;\n const height = size\n ? Math.max(MIN_HEIGHT, size.height)\n : element.offsetHeight;\n\n return {\n x: Math.max(0, Math.min(x, container.clientWidth - width)),\n y: Math.max(0, Math.min(y, container.clientHeight - height)),\n };\n}\n\nexport function resizeWindowWithinContainer(\n resizeState: WindowResizeState,\n clientX: number,\n clientY: number,\n container: HTMLElement | null,\n) {\n const deltaX = clientX - resizeState.startX;\n const deltaY = clientY - resizeState.startY;\n const { edge } = resizeState;\n const movesLeft = edge.includes(\"w\");\n const movesUp = edge.includes(\"n\");\n // A side handle drags one edge, so the other axis keeps its start size.\n const resizesX = movesLeft || edge.includes(\"e\");\n const resizesY = movesUp || edge.includes(\"s\");\n let width = Math.max(\n MIN_WIDTH,\n resizeState.startWidth + (resizesX ? deltaX * (movesLeft ? -1 : 1) : 0),\n );\n let height = Math.max(\n MIN_HEIGHT,\n resizeState.startHeight + (resizesY ? deltaY * (movesUp ? -1 : 1) : 0),\n );\n let x = movesLeft\n ? resizeState.startLeft + resizeState.startWidth - width\n : resizeState.startLeft;\n let y = movesUp\n ? resizeState.startTop + resizeState.startHeight - height\n : resizeState.startTop;\n\n if (container) {\n if (x < 0) {\n width += x;\n x = 0;\n }\n if (y < 0) {\n height += y;\n y = 0;\n }\n width = Math.min(width, container.clientWidth - x - resizeState.borderX);\n height = Math.min(height, container.clientHeight - y - resizeState.borderY);\n width = Math.max(MIN_WIDTH, width);\n height = Math.max(MIN_HEIGHT, height);\n }\n\n return {\n position: { x, y },\n size: { width, height },\n };\n}\n"]}