@tearleads/windowing 0.1.1

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 (148) hide show
  1. package/README.md +155 -0
  2. package/createRequiredContext.d.ts +16 -0
  3. package/createRequiredContext.js +22 -0
  4. package/createRequiredContext.js.map +1 -0
  5. package/index.d.ts +13 -0
  6. package/index.js +17 -0
  7. package/index.js.map +1 -0
  8. package/menu/Menu.css +105 -0
  9. package/menu/Menu.d.ts +11 -0
  10. package/menu/Menu.js +175 -0
  11. package/menu/Menu.js.map +1 -0
  12. package/menu/MenuItem.d.ts +9 -0
  13. package/menu/MenuItem.js +5 -0
  14. package/menu/MenuItem.js.map +1 -0
  15. package/menu/useContextMenuState.d.ts +20 -0
  16. package/menu/useContextMenuState.js +45 -0
  17. package/menu/useContextMenuState.js.map +1 -0
  18. package/menu/useMenuKeyboard.d.ts +2 -0
  19. package/menu/useMenuKeyboard.js +90 -0
  20. package/menu/useMenuKeyboard.js.map +1 -0
  21. package/package.json +27 -0
  22. package/sidebar/SidebarResize.css +31 -0
  23. package/sidebar/SidebarResize.d.ts +18 -0
  24. package/sidebar/SidebarResize.js +115 -0
  25. package/sidebar/SidebarResize.js.map +1 -0
  26. package/tokens.css +63 -0
  27. package/window/CurrentWindowContext.d.ts +27 -0
  28. package/window/CurrentWindowContext.js +31 -0
  29. package/window/CurrentWindowContext.js.map +1 -0
  30. package/window/Window.css +32 -0
  31. package/window/Window.d.ts +11 -0
  32. package/window/Window.js +206 -0
  33. package/window/Window.js.map +1 -0
  34. package/window/WindowBody.css +21 -0
  35. package/window/WindowBody.d.ts +8 -0
  36. package/window/WindowBody.js +10 -0
  37. package/window/WindowBody.js.map +1 -0
  38. package/window/WindowChromeActions.d.ts +55 -0
  39. package/window/WindowChromeActions.js +61 -0
  40. package/window/WindowChromeActions.js.map +1 -0
  41. package/window/WindowCloseButton.d.ts +6 -0
  42. package/window/WindowCloseButton.js +9 -0
  43. package/window/WindowCloseButton.js.map +1 -0
  44. package/window/WindowMaximizeButton.d.ts +3 -0
  45. package/window/WindowMaximizeButton.js +5 -0
  46. package/window/WindowMaximizeButton.js.map +1 -0
  47. package/window/WindowMenuBar.css +63 -0
  48. package/window/WindowMenuBar.d.ts +14 -0
  49. package/window/WindowMenuBar.js +37 -0
  50. package/window/WindowMenuBar.js.map +1 -0
  51. package/window/WindowMenuContext.d.ts +46 -0
  52. package/window/WindowMenuContext.js +208 -0
  53. package/window/WindowMenuContext.js.map +1 -0
  54. package/window/WindowMinimizeButton.d.ts +3 -0
  55. package/window/WindowMinimizeButton.js +5 -0
  56. package/window/WindowMinimizeButton.js.map +1 -0
  57. package/window/WindowResizeHandle.css +65 -0
  58. package/window/WindowResizeHandle.d.ts +5 -0
  59. package/window/WindowResizeHandle.js +6 -0
  60. package/window/WindowResizeHandle.js.map +1 -0
  61. package/window/WindowSidebar.css +37 -0
  62. package/window/WindowSidebar.d.ts +6 -0
  63. package/window/WindowSidebar.js +9 -0
  64. package/window/WindowSidebar.js.map +1 -0
  65. package/window/WindowSidebarContext.d.ts +14 -0
  66. package/window/WindowSidebarContext.js +43 -0
  67. package/window/WindowSidebarContext.js.map +1 -0
  68. package/window/WindowStateProvider/WindowStateProvider.d.ts +2 -0
  69. package/window/WindowStateProvider/WindowStateProvider.js +16 -0
  70. package/window/WindowStateProvider/WindowStateProvider.js.map +1 -0
  71. package/window/WindowStateProvider/context.d.ts +4 -0
  72. package/window/WindowStateProvider/context.js +7 -0
  73. package/window/WindowStateProvider/context.js.map +1 -0
  74. package/window/WindowStateProvider/index.d.ts +5 -0
  75. package/window/WindowStateProvider/index.js +5 -0
  76. package/window/WindowStateProvider/index.js.map +1 -0
  77. package/window/WindowStateProvider/types.d.ts +58 -0
  78. package/window/WindowStateProvider/types.js +2 -0
  79. package/window/WindowStateProvider/types.js.map +1 -0
  80. package/window/WindowStateProvider/useWindowActions.d.ts +1 -0
  81. package/window/WindowStateProvider/useWindowActions.js +3 -0
  82. package/window/WindowStateProvider/useWindowActions.js.map +1 -0
  83. package/window/WindowStateProvider/useWindowStateActions.d.ts +24 -0
  84. package/window/WindowStateProvider/useWindowStateActions.js +176 -0
  85. package/window/WindowStateProvider/useWindowStateActions.js.map +1 -0
  86. package/window/WindowStateProvider/useWindowStateData.d.ts +1 -0
  87. package/window/WindowStateProvider/useWindowStateData.js +3 -0
  88. package/window/WindowStateProvider/useWindowStateData.js.map +1 -0
  89. package/window/WindowStateProvider/util/bringWindowToFront.d.ts +2 -0
  90. package/window/WindowStateProvider/util/bringWindowToFront.js +21 -0
  91. package/window/WindowStateProvider/util/bringWindowToFront.js.map +1 -0
  92. package/window/WindowStateProvider/util/createWindowEntry.d.ts +3 -0
  93. package/window/WindowStateProvider/util/createWindowEntry.js +20 -0
  94. package/window/WindowStateProvider/util/createWindowEntry.js.map +1 -0
  95. package/window/WindowStateProvider/util/findAdjacentWindow.d.ts +2 -0
  96. package/window/WindowStateProvider/util/findAdjacentWindow.js +22 -0
  97. package/window/WindowStateProvider/util/findAdjacentWindow.js.map +1 -0
  98. package/window/WindowStateProvider/util/findTopWindow.d.ts +3 -0
  99. package/window/WindowStateProvider/util/findTopWindow.js +7 -0
  100. package/window/WindowStateProvider/util/findTopWindow.js.map +1 -0
  101. package/window/WindowStateProvider/util/getMaxWindowZIndex.d.ts +2 -0
  102. package/window/WindowStateProvider/util/getMaxWindowZIndex.js +4 -0
  103. package/window/WindowStateProvider/util/getMaxWindowZIndex.js.map +1 -0
  104. package/window/WindowStateProvider/util/index.d.ts +6 -0
  105. package/window/WindowStateProvider/util/index.js +7 -0
  106. package/window/WindowStateProvider/util/index.js.map +1 -0
  107. package/window/WindowStateProvider/util/swapWindowZIndexes.d.ts +2 -0
  108. package/window/WindowStateProvider/util/swapWindowZIndexes.js +21 -0
  109. package/window/WindowStateProvider/util/swapWindowZIndexes.js.map +1 -0
  110. package/window/WindowStateProvider/util/updateWindowFlag.d.ts +2 -0
  111. package/window/WindowStateProvider/util/updateWindowFlag.js +4 -0
  112. package/window/WindowStateProvider/util/updateWindowFlag.js.map +1 -0
  113. package/window/WindowStatusBar.css +40 -0
  114. package/window/WindowStatusBar.d.ts +4 -0
  115. package/window/WindowStatusBar.js +20 -0
  116. package/window/WindowStatusBar.js.map +1 -0
  117. package/window/WindowTitleBar.css +88 -0
  118. package/window/WindowTitleBar.d.ts +18 -0
  119. package/window/WindowTitleBar.js +36 -0
  120. package/window/WindowTitleBar.js.map +1 -0
  121. package/window/WindowToolBar.css +75 -0
  122. package/window/WindowToolBar.d.ts +38 -0
  123. package/window/WindowToolBar.js +68 -0
  124. package/window/WindowToolBar.js.map +1 -0
  125. package/window/useWindowGeometry.d.ts +16 -0
  126. package/window/useWindowGeometry.js +243 -0
  127. package/window/useWindowGeometry.js.map +1 -0
  128. package/window/useWindowItemRegistration.d.ts +10 -0
  129. package/window/useWindowItemRegistration.js +46 -0
  130. package/window/useWindowItemRegistration.js.map +1 -0
  131. package/window/useWindowItemRegistry.d.ts +12 -0
  132. package/window/useWindowItemRegistry.js +45 -0
  133. package/window/useWindowItemRegistry.js.map +1 -0
  134. package/window/useWindowKeyboardGeometry.d.ts +21 -0
  135. package/window/useWindowKeyboardGeometry.js +139 -0
  136. package/window/useWindowKeyboardGeometry.js.map +1 -0
  137. package/window/useWindowLayout.d.ts +18 -0
  138. package/window/useWindowLayout.js +115 -0
  139. package/window/useWindowLayout.js.map +1 -0
  140. package/window/useWindowToolbarReservationRegistry.d.ts +8 -0
  141. package/window/useWindowToolbarReservationRegistry.js +19 -0
  142. package/window/useWindowToolbarReservationRegistry.js.map +1 -0
  143. package/window/windowGeometry.d.ts +36 -0
  144. package/window/windowGeometry.js +54 -0
  145. package/window/windowGeometry.js.map +1 -0
  146. package/window/windowMenuRegistrations.d.ts +18 -0
  147. package/window/windowMenuRegistrations.js +34 -0
  148. package/window/windowMenuRegistrations.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWindowGeometry.js","sourceRoot":"","sources":["../../../../../../../Users/a2f0/github/tearleads5/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 { 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"]}
@@ -0,0 +1,10 @@
1
+ type WindowItemAction = () => unknown;
2
+ interface WindowItemRegistrationOptions<Input, RegisteredItem extends object> {
3
+ action: WindowItemAction | null;
4
+ createRegisteredItem: (input: Input, handleAction: WindowItemAction) => RegisteredItem | null;
5
+ input: Input | null;
6
+ registerItem: (id: object, item: RegisteredItem) => void;
7
+ unregisterItem: (id: object) => void;
8
+ }
9
+ export declare function useWindowItemRegistration<Input, RegisteredItem extends object>(options: WindowItemRegistrationOptions<Input, RegisteredItem>): void;
10
+ export {};
@@ -0,0 +1,46 @@
1
+ import { useCallback, useEffect, useLayoutEffect, useRef } from "react";
2
+ import { sameWindowItem } from "./useWindowItemRegistry.js";
3
+ export function useWindowItemRegistration(options) {
4
+ const { action, createRegisteredItem, input, registerItem, unregisterItem } = options;
5
+ const actionRef = useRef(null);
6
+ const activeRegistrationRef = useRef(null);
7
+ const registrationIdRef = useRef({});
8
+ useLayoutEffect(() => {
9
+ actionRef.current = action;
10
+ }, [action]);
11
+ const handleAction = useCallback(() => actionRef.current?.(), []);
12
+ const registeredItem = input === null ? null : createRegisteredItem(input, handleAction);
13
+ useEffect(() => {
14
+ const activeRegistration = activeRegistrationRef.current;
15
+ const activeItem = activeRegistration?.item ?? null;
16
+ const itemMatches = activeItem === registeredItem ||
17
+ (activeItem !== null &&
18
+ registeredItem !== null &&
19
+ sameWindowItem(activeItem, registeredItem));
20
+ if (itemMatches &&
21
+ activeRegistration?.registerItem === registerItem &&
22
+ activeRegistration.unregisterItem === unregisterItem) {
23
+ return;
24
+ }
25
+ const registrationId = registrationIdRef.current;
26
+ if (activeRegistration?.item) {
27
+ activeRegistration.unregisterItem(registrationId);
28
+ }
29
+ if (registeredItem) {
30
+ registerItem(registrationId, registeredItem);
31
+ }
32
+ activeRegistrationRef.current = {
33
+ item: registeredItem,
34
+ registerItem,
35
+ unregisterItem,
36
+ };
37
+ });
38
+ useEffect(() => () => {
39
+ const activeRegistration = activeRegistrationRef.current;
40
+ if (activeRegistration?.item) {
41
+ activeRegistration.unregisterItem(registrationIdRef.current);
42
+ }
43
+ activeRegistrationRef.current = null;
44
+ }, []);
45
+ }
46
+ //# sourceMappingURL=useWindowItemRegistration.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,12 @@
1
+ interface WindowItemRegistry<T> {
2
+ items: ReadonlyMap<object, T>;
3
+ registerItem: (id: object, item: T) => void;
4
+ unregisterItem: (id: object) => void;
5
+ }
6
+ export declare function sameWindowItem<T extends object>(left: T | undefined, right: T): boolean;
7
+ export declare function useWindowItemRegistry<T>(sameItem: (left: T | undefined, right: T) => boolean): WindowItemRegistry<T>;
8
+ /** Highest priority wins among registered items; null when none registered. */
9
+ export declare function selectHighestPriorityItem<T extends {
10
+ priority: number;
11
+ }>(items: ReadonlyMap<object, T>): T | null;
12
+ export {};
@@ -0,0 +1,45 @@
1
+ import { useCallback, useMemo, useState } from "react";
2
+ export function sameWindowItem(left, right) {
3
+ if (!left) {
4
+ return false;
5
+ }
6
+ const leftEntries = Object.entries(left);
7
+ const rightEntries = Object.entries(right);
8
+ return (leftEntries.length === rightEntries.length &&
9
+ rightEntries.every(([rightKey, rightValue]) => leftEntries.some(([leftKey, leftValue]) => leftKey === rightKey && Object.is(leftValue, rightValue))));
10
+ }
11
+ export function useWindowItemRegistry(sameItem) {
12
+ const [items, setItems] = useState(() => new Map());
13
+ const registerItem = useCallback((id, item) => {
14
+ setItems((currentItems) => {
15
+ if (sameItem(currentItems.get(id), item)) {
16
+ return currentItems;
17
+ }
18
+ const nextItems = new Map(currentItems);
19
+ nextItems.set(id, item);
20
+ return nextItems;
21
+ });
22
+ }, [sameItem]);
23
+ const unregisterItem = useCallback((id) => {
24
+ setItems((currentItems) => {
25
+ if (!currentItems.has(id)) {
26
+ return currentItems;
27
+ }
28
+ const nextItems = new Map(currentItems);
29
+ nextItems.delete(id);
30
+ return nextItems;
31
+ });
32
+ }, []);
33
+ return useMemo(() => ({ items, registerItem, unregisterItem }), [items, registerItem, unregisterItem]);
34
+ }
35
+ /** Highest priority wins among registered items; null when none registered. */
36
+ export function selectHighestPriorityItem(items) {
37
+ let selected = null;
38
+ for (const item of items.values()) {
39
+ if (!selected || item.priority > selected.priority) {
40
+ selected = item;
41
+ }
42
+ }
43
+ return selected;
44
+ }
45
+ //# sourceMappingURL=useWindowItemRegistry.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,21 @@
1
+ import { type RefObject } from "react";
2
+ import type { WindowMenuItem } from "./WindowMenuBar.js";
3
+ import type { LiveGeometry } from "./windowGeometry.js";
4
+ interface SteppedGeometry {
5
+ commit: () => void;
6
+ grow: (deltaWidth: number, deltaHeight: number) => void;
7
+ hold: (holding: boolean) => void;
8
+ nudge: (deltaX: number, deltaY: number) => void;
9
+ restore: (saved: LiveGeometry) => void;
10
+ snapshot: () => LiveGeometry;
11
+ }
12
+ export declare function useWindowGeometryMenuItems(stepped: SteppedGeometry, { maximized, minimized, windowRef, }: {
13
+ maximized: boolean;
14
+ minimized: boolean;
15
+ windowRef: RefObject<HTMLElement | null>;
16
+ }, announce: (message: string) => void): WindowMenuItem[];
17
+ export declare function useFocusWindowOnShow(windowRef: RefObject<HTMLElement | null>, { isTop, shown }: {
18
+ isTop: boolean;
19
+ shown: boolean;
20
+ }): void;
21
+ export {};
@@ -0,0 +1,139 @@
1
+ import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
2
+ const STEP_PX = 10;
3
+ const ARROW_DIRECTIONS = {
4
+ ArrowDown: [0, 1],
5
+ ArrowLeft: [-1, 0],
6
+ ArrowRight: [1, 0],
7
+ ArrowUp: [0, -1],
8
+ };
9
+ const MODE_HINTS = {
10
+ move: "Moving window: arrow keys move it, Enter keeps it, Escape cancels.",
11
+ resize: "Resizing window: arrow keys resize it, Enter keeps it, Escape cancels.",
12
+ };
13
+ // Keyboard move and resize, entered from the window's View menu the way a
14
+ // desktop system menu offers them. Arrow keys step the window, Enter keeps the
15
+ // result, and Escape puts it back. Keys are captured only while a mode is
16
+ // active, so no shortcut competes with text editing inside the window. The
17
+ // mode focuses its window and ends, keeping the result, as soon as focus moves
18
+ // off the window itself (to a control inside it or anything else) or a pointer
19
+ // presses anywhere; minimizing or maximizing the window cancels it, so its key
20
+ // capture never outlives the window it moves.
21
+ function useWindowKeyboardGeometry({ commit, grow, hold, nudge, restore, snapshot }, { available, windowRef }, announce) {
22
+ const [mode, setMode] = useState(null);
23
+ const startGeometry = useRef(null);
24
+ const startKeyboardMode = useCallback((nextMode) => {
25
+ startGeometry.current = snapshot();
26
+ hold(true);
27
+ setMode(nextMode);
28
+ announce(MODE_HINTS[nextMode]);
29
+ windowRef.current?.focus({ preventScroll: true });
30
+ }, [announce, hold, snapshot, windowRef]);
31
+ useEffect(() => {
32
+ if (available || !mode) {
33
+ return;
34
+ }
35
+ if (startGeometry.current) {
36
+ restore(startGeometry.current);
37
+ }
38
+ hold(false);
39
+ setMode(null);
40
+ }, [available, hold, mode, restore]);
41
+ useEffect(() => {
42
+ if (!mode) {
43
+ return;
44
+ }
45
+ function leave() {
46
+ commit();
47
+ hold(false);
48
+ setMode(null);
49
+ }
50
+ function handleFocusIn(event) {
51
+ if (event.target !== windowRef.current) {
52
+ leave();
53
+ }
54
+ }
55
+ function finish(event, keep) {
56
+ event.preventDefault();
57
+ event.stopPropagation();
58
+ if (keep) {
59
+ commit();
60
+ }
61
+ else if (startGeometry.current) {
62
+ restore(startGeometry.current);
63
+ }
64
+ hold(false);
65
+ setMode(null);
66
+ }
67
+ function handleKeyDown(event) {
68
+ const direction = ARROW_DIRECTIONS[event.key];
69
+ if (direction) {
70
+ event.preventDefault();
71
+ event.stopPropagation();
72
+ const [x, y] = direction;
73
+ if (mode === "move") {
74
+ nudge(x * STEP_PX, y * STEP_PX);
75
+ }
76
+ else {
77
+ grow(x * STEP_PX, y * STEP_PX);
78
+ }
79
+ return;
80
+ }
81
+ if (event.key === "Enter") {
82
+ finish(event, true);
83
+ }
84
+ else if (event.key === "Escape") {
85
+ finish(event, false);
86
+ }
87
+ }
88
+ document.addEventListener("keydown", handleKeyDown, true);
89
+ document.addEventListener("pointerdown", leave, true);
90
+ document.addEventListener("focusin", handleFocusIn, true);
91
+ return () => {
92
+ document.removeEventListener("keydown", handleKeyDown, true);
93
+ document.removeEventListener("pointerdown", leave, true);
94
+ document.removeEventListener("focusin", handleFocusIn, true);
95
+ };
96
+ }, [commit, grow, hold, mode, nudge, restore, windowRef]);
97
+ return startKeyboardMode;
98
+ }
99
+ // The View menu entries that start keyboard move and resize.
100
+ export function useWindowGeometryMenuItems(stepped, { maximized, minimized, windowRef, }, announce) {
101
+ const startKeyboardMode = useWindowKeyboardGeometry(stepped, { available: !maximized && !minimized, windowRef }, announce);
102
+ return useMemo(() => [
103
+ {
104
+ disabled: maximized,
105
+ id: "keyboard-move",
106
+ label: "Move Window",
107
+ onClick: () => startKeyboardMode("move"),
108
+ },
109
+ {
110
+ disabled: maximized,
111
+ id: "keyboard-resize",
112
+ label: "Resize Window",
113
+ onClick: () => startKeyboardMode("resize"),
114
+ },
115
+ ], [maximized, startKeyboardMode]);
116
+ }
117
+ // Moves focus into a window when it opens or comes back from minimized, unless
118
+ // focus is already inside it, such as an autofocused field. `shown` must only
119
+ // turn true once the window is laid out and visible: browsers ignore focus on
120
+ // an element that is still `visibility: hidden`. Only the foremost window takes
121
+ // focus, so windows remounting together leave it on the front one.
122
+ export function useFocusWindowOnShow(windowRef, { isTop, shown }) {
123
+ const hidden = useRef(true);
124
+ useEffect(() => {
125
+ if (!shown) {
126
+ hidden.current = true;
127
+ return;
128
+ }
129
+ if (!hidden.current) {
130
+ return;
131
+ }
132
+ hidden.current = false;
133
+ const root = windowRef.current;
134
+ if (isTop && root && !root.contains(document.activeElement)) {
135
+ root.focus({ preventScroll: true });
136
+ }
137
+ }, [isTop, shown, windowRef]);
138
+ }
139
+ //# sourceMappingURL=useWindowKeyboardGeometry.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,18 @@
1
+ import { type MutableRefObject, type RefObject } from "react";
2
+ import type { WindowEntry, WindowPosition, WindowSize } from "./WindowStateProvider/index.js";
3
+ import { type LiveGeometry, type WindowDragState, type WindowResizeState } from "./windowGeometry.js";
4
+ interface WindowLayoutInput {
5
+ clamp: (x: number, y: number) => WindowPosition;
6
+ commit: () => void;
7
+ dragging: MutableRefObject<WindowDragState | null>;
8
+ entry: WindowEntry;
9
+ live: MutableRefObject<LiveGeometry>;
10
+ resizing: MutableRefObject<WindowResizeState | null>;
11
+ setPosition: (value: WindowPosition) => void;
12
+ size: WindowSize | null;
13
+ windowRef: RefObject<HTMLElement | null>;
14
+ }
15
+ export declare function useWindowLayout({ clamp, commit, dragging, entry, live, resizing, setPosition, size, windowRef, }: WindowLayoutInput): {
16
+ hold: (holding: boolean) => void;
17
+ };
18
+ export {};
@@ -0,0 +1,115 @@
1
+ import { useCallback, useEffect, useRef, } from "react";
2
+ import { clampWindowPosition, } from "./windowGeometry.js";
3
+ // A gesture (a pointer drag or resize, or a keyboard move or resize) owns the
4
+ // live geometry until it ends: layout holds off meanwhile, so it never commits
5
+ // an unconfirmed frame, and runs once when the gesture lets go.
6
+ function useGestureHold(dragging, resizing) {
7
+ const held = useRef(false);
8
+ const deferred = useRef(false);
9
+ const isBusy = useCallback(() => held.current || dragging.current !== null || resizing.current !== null, [dragging, resizing]);
10
+ return { deferred, held, isBusy };
11
+ }
12
+ // A surface with no size is hidden (display: none), so nothing measured
13
+ // against it is meaningful.
14
+ function isUnsized(container) {
15
+ return container.clientWidth === 0 && container.clientHeight === 0;
16
+ }
17
+ // The surface changing size (a workspace shown after being hidden, a resized
18
+ // viewport) lays the window out again.
19
+ function useSurfaceObserver(windowRef, minimized, layout) {
20
+ useEffect(() => {
21
+ const container = windowRef.current?.parentElement;
22
+ if (minimized || !container || typeof ResizeObserver === "undefined") {
23
+ return;
24
+ }
25
+ const observer = new ResizeObserver(() => layout());
26
+ observer.observe(container);
27
+ return () => observer.disconnect();
28
+ }, [layout, minimized, windowRef]);
29
+ }
30
+ export function useWindowLayout({ clamp, commit, dragging, entry, live, resizing, setPosition, size, windowRef, }) {
31
+ // Lay the window out from its committed position, or from its viewport
32
+ // starting point the first time, and commit where it actually landed. A
33
+ // minimized window has no element to measure and a maximized one measures at
34
+ // full size, so this waits both out. A hidden surface (an inactive
35
+ // workspace) measures at zero: the window takes its intended position
36
+ // unclamped and nothing is committed until the surface has a size.
37
+ const { deferred, held, isBusy } = useGestureHold(dragging, resizing);
38
+ // `release` lays out from the live geometry a gesture just finished with,
39
+ // which the committed position does not reflect until it re-renders.
40
+ const layout = useCallback((release = false) => {
41
+ const element = windowRef.current;
42
+ const container = element?.parentElement;
43
+ if (entry.minimized || entry.maximized || !element || !container) {
44
+ return;
45
+ }
46
+ if (isBusy()) {
47
+ deferred.current = true;
48
+ return;
49
+ }
50
+ if (!live.current.size) {
51
+ // A cleared size has not re-rendered yet; drop the old inline size so the
52
+ // window measures at the stylesheet default it is about to take.
53
+ element.style.removeProperty("width");
54
+ element.style.removeProperty("height");
55
+ }
56
+ const containerRect = container.getBoundingClientRect();
57
+ const start = (release ? live.current.position : null) ??
58
+ entry.position ?? {
59
+ x: entry.initialX - containerRect.left,
60
+ y: entry.initialY - containerRect.top,
61
+ };
62
+ if (isUnsized(container)) {
63
+ setPosition(start);
64
+ return;
65
+ }
66
+ setPosition(clamp(start.x, start.y));
67
+ commit();
68
+ }, [
69
+ clamp,
70
+ commit,
71
+ deferred,
72
+ entry.initialX,
73
+ entry.initialY,
74
+ entry.maximized,
75
+ entry.minimized,
76
+ entry.position,
77
+ isBusy,
78
+ live,
79
+ setPosition,
80
+ windowRef,
81
+ ]);
82
+ useEffect(() => {
83
+ layout();
84
+ }, [layout]);
85
+ useSurfaceObserver(windowRef, entry.minimized, layout);
86
+ // Once the window renders at a new size, including a cleared size falling
87
+ // back to its stylesheet default, keep it inside the surface.
88
+ useEffect(() => {
89
+ const current = live.current.position;
90
+ const container = windowRef.current?.parentElement;
91
+ if (!current ||
92
+ entry.maximized ||
93
+ isBusy() ||
94
+ !container ||
95
+ isUnsized(container)) {
96
+ return;
97
+ }
98
+ const clamped = clampWindowPosition(windowRef.current, current.x, current.y, size);
99
+ if (clamped.x !== current.x || clamped.y !== current.y) {
100
+ setPosition(clamped);
101
+ commit();
102
+ }
103
+ }, [commit, entry.maximized, isBusy, live, setPosition, size, windowRef]);
104
+ // Holds layout for a keyboard gesture; releasing it runs any layout the
105
+ // gesture deferred.
106
+ const hold = useCallback((holding) => {
107
+ held.current = holding;
108
+ if (!holding && deferred.current) {
109
+ deferred.current = false;
110
+ layout(true);
111
+ }
112
+ }, [deferred, held, layout]);
113
+ return { hold };
114
+ }
115
+ //# sourceMappingURL=useWindowLayout.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,8 @@
1
+ interface WindowToolbarReservationRegistry {
2
+ register: (id: object, reserved: boolean) => void;
3
+ released: boolean;
4
+ reserved: boolean;
5
+ unregister: (id: object) => void;
6
+ }
7
+ export declare function useWindowToolbarReservationRegistry(): WindowToolbarReservationRegistry;
8
+ export {};
@@ -0,0 +1,19 @@
1
+ import { useMemo } from "react";
2
+ import { useWindowItemRegistry } from "./useWindowItemRegistry.js";
3
+ // Module scope on purpose: the registry keys its callback identities on the
4
+ // comparator, so an inline closure here re-registers every render and loops.
5
+ function sameToolbarReservation(left, right) {
6
+ return left === right;
7
+ }
8
+ export function useWindowToolbarReservationRegistry() {
9
+ const reservation = useWindowItemRegistry(sameToolbarReservation);
10
+ const reserved = Array.from(reservation.items.values()).some(Boolean);
11
+ const released = reservation.items.size > 0 && !reserved;
12
+ return useMemo(() => ({
13
+ register: reservation.registerItem,
14
+ released,
15
+ reserved,
16
+ unregister: reservation.unregisterItem,
17
+ }), [released, reserved, reservation.registerItem, reservation.unregisterItem]);
18
+ }
19
+ //# sourceMappingURL=useWindowToolbarReservationRegistry.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,36 @@
1
+ import type { ResizeCorner } from "./WindowResizeHandle.js";
2
+ import type { WindowPosition, WindowSize } from "./WindowStateProvider/index.js";
3
+ export declare const MIN_WIDTH = 200;
4
+ export declare const MIN_HEIGHT = 100;
5
+ export interface WindowDragState {
6
+ offsetX: number;
7
+ offsetY: number;
8
+ pointerId: number;
9
+ }
10
+ export interface WindowResizeState {
11
+ corner: ResizeCorner;
12
+ pointerId: number;
13
+ startHeight: number;
14
+ startLeft: number;
15
+ startTop: number;
16
+ startWidth: number;
17
+ startX: number;
18
+ startY: number;
19
+ borderX: number;
20
+ borderY: number;
21
+ }
22
+ export interface LiveGeometry {
23
+ position: WindowPosition | null;
24
+ size: WindowSize | null;
25
+ }
26
+ export declare function clampWindowPosition(element: HTMLElement | null, x: number, y: number, size: WindowSize | null): WindowPosition;
27
+ export declare function resizeWindowWithinContainer(resizeState: WindowResizeState, clientX: number, clientY: number, container: HTMLElement | null): {
28
+ position: {
29
+ x: number;
30
+ y: number;
31
+ };
32
+ size: {
33
+ width: number;
34
+ height: number;
35
+ };
36
+ };