@witchcraft/layout 0.0.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.
- package/README.md +474 -0
- package/dist/module.d.mts +14 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +26 -0
- package/dist/runtime/components/LayoutDecos.d.vue.ts +0 -0
- package/dist/runtime/components/LayoutDecos.vue +54 -0
- package/dist/runtime/components/LayoutDecos.vue.d.ts +0 -0
- package/dist/runtime/components/LayoutEdges.d.vue.ts +0 -0
- package/dist/runtime/components/LayoutEdges.vue +145 -0
- package/dist/runtime/components/LayoutEdges.vue.d.ts +0 -0
- package/dist/runtime/components/LayoutFrame.d.vue.ts +0 -0
- package/dist/runtime/components/LayoutFrame.vue +41 -0
- package/dist/runtime/components/LayoutFrame.vue.d.ts +0 -0
- package/dist/runtime/components/LayoutShapeSquare.d.vue.ts +0 -0
- package/dist/runtime/components/LayoutShapeSquare.vue +36 -0
- package/dist/runtime/components/LayoutShapeSquare.vue.d.ts +0 -0
- package/dist/runtime/components/LayoutWindow.d.vue.ts +0 -0
- package/dist/runtime/components/LayoutWindow.vue +183 -0
- package/dist/runtime/components/LayoutWindow.vue.d.ts +0 -0
- package/dist/runtime/composables/useFrames.d.ts +0 -0
- package/dist/runtime/composables/useFrames.js +184 -0
- package/dist/runtime/demo/App.d.vue.ts +0 -0
- package/dist/runtime/demo/App.vue +121 -0
- package/dist/runtime/demo/App.vue.d.ts +0 -0
- package/dist/runtime/demo/DemoControls.d.vue.ts +0 -0
- package/dist/runtime/demo/DemoControls.vue +14 -0
- package/dist/runtime/demo/DemoControls.vue.d.ts +0 -0
- package/dist/runtime/demo/README.md +1 -0
- package/dist/runtime/demo/main.d.ts +0 -0
- package/dist/runtime/demo/main.js +4 -0
- package/dist/runtime/demo/sharedLayoutInstance.d.ts +0 -0
- package/dist/runtime/demo/sharedLayoutInstance.js +5 -0
- package/dist/runtime/demo/tailwind.css +1 -0
- package/dist/runtime/drag/CloseAction.d.ts +0 -0
- package/dist/runtime/drag/CloseAction.js +121 -0
- package/dist/runtime/drag/DragActionHandler.d.ts +0 -0
- package/dist/runtime/drag/DragActionHandler.js +83 -0
- package/dist/runtime/drag/DragDirectionStore.d.ts +0 -0
- package/dist/runtime/drag/DragDirectionStore.js +45 -0
- package/dist/runtime/drag/SplitAction.d.ts +0 -0
- package/dist/runtime/drag/SplitAction.js +110 -0
- package/dist/runtime/drag/types.d.ts +0 -0
- package/dist/runtime/drag/types.js +0 -0
- package/dist/runtime/helpers/addPointsToIntersection.d.ts +0 -0
- package/dist/runtime/helpers/addPointsToIntersection.js +7 -0
- package/dist/runtime/helpers/assertEdgeSorted.d.ts +0 -0
- package/dist/runtime/helpers/assertEdgeSorted.js +7 -0
- package/dist/runtime/helpers/assertItemIn.d.ts +0 -0
- package/dist/runtime/helpers/assertItemIn.js +8 -0
- package/dist/runtime/helpers/assertItemNotIn.d.ts +0 -0
- package/dist/runtime/helpers/assertItemNotIn.js +7 -0
- package/dist/runtime/helpers/assertLayoutHasActiveWindow.d.ts +0 -0
- package/dist/runtime/helpers/assertLayoutHasActiveWindow.js +7 -0
- package/dist/runtime/helpers/assertValidWinAndFrame.d.ts +0 -0
- package/dist/runtime/helpers/assertValidWinAndFrame.js +5 -0
- package/dist/runtime/helpers/assertValidWinAndFrameIds.d.ts +0 -0
- package/dist/runtime/helpers/assertValidWinAndFrameIds.js +6 -0
- package/dist/runtime/helpers/assertWindowHasActiveFrame.d.ts +0 -0
- package/dist/runtime/helpers/assertWindowHasActiveFrame.js +7 -0
- package/dist/runtime/helpers/clampNumber.d.ts +0 -0
- package/dist/runtime/helpers/clampNumber.js +3 -0
- package/dist/runtime/helpers/cloneFrame.d.ts +0 -0
- package/dist/runtime/helpers/cloneFrame.js +3 -0
- package/dist/runtime/helpers/cloneFrames.d.ts +0 -0
- package/dist/runtime/helpers/cloneFrames.js +16 -0
- package/dist/runtime/helpers/containsEdge.d.ts +0 -0
- package/dist/runtime/helpers/containsEdge.js +13 -0
- package/dist/runtime/helpers/convertLayoutWindowToWorkspace.d.ts +0 -0
- package/dist/runtime/helpers/convertLayoutWindowToWorkspace.js +10 -0
- package/dist/runtime/helpers/copySize.d.ts +0 -0
- package/dist/runtime/helpers/copySize.js +5 -0
- package/dist/runtime/helpers/createEdge.d.ts +0 -0
- package/dist/runtime/helpers/createEdge.js +13 -0
- package/dist/runtime/helpers/dirToOrientation.d.ts +0 -0
- package/dist/runtime/helpers/dirToOrientation.js +10 -0
- package/dist/runtime/helpers/dirToSide.d.ts +0 -0
- package/dist/runtime/helpers/dirToSide.js +5 -0
- package/dist/runtime/helpers/doEdgesOverlap.d.ts +0 -0
- package/dist/runtime/helpers/doEdgesOverlap.js +22 -0
- package/dist/runtime/helpers/doesEdgeContinueEdge.d.ts +0 -0
- package/dist/runtime/helpers/doesEdgeContinueEdge.js +17 -0
- package/dist/runtime/helpers/edgeToPoints.d.ts +0 -0
- package/dist/runtime/helpers/edgeToPoints.js +3 -0
- package/dist/runtime/helpers/findDraggableEdge.d.ts +0 -0
- package/dist/runtime/helpers/findDraggableEdge.js +13 -0
- package/dist/runtime/helpers/findFrameDraggableEdges.d.ts +0 -0
- package/dist/runtime/helpers/findFrameDraggableEdges.js +18 -0
- package/dist/runtime/helpers/frameToEdges.d.ts +0 -0
- package/dist/runtime/helpers/frameToEdges.js +21 -0
- package/dist/runtime/helpers/frameToPoints.d.ts +0 -0
- package/dist/runtime/helpers/frameToPoints.js +7 -0
- package/dist/runtime/helpers/getEdgeOrientation.d.ts +0 -0
- package/dist/runtime/helpers/getEdgeOrientation.js +4 -0
- package/dist/runtime/helpers/getEdgeSharedDirection.d.ts +0 -0
- package/dist/runtime/helpers/getEdgeSharedDirection.js +7 -0
- package/dist/runtime/helpers/getEdgeSide.d.ts +0 -0
- package/dist/runtime/helpers/getEdgeSide.js +16 -0
- package/dist/runtime/helpers/getFrameById.d.ts +0 -0
- package/dist/runtime/helpers/getFrameById.js +5 -0
- package/dist/runtime/helpers/getFrameConstant.d.ts +0 -0
- package/dist/runtime/helpers/getFrameConstant.js +15 -0
- package/dist/runtime/helpers/getIntersections.d.ts +0 -0
- package/dist/runtime/helpers/getIntersections.js +63 -0
- package/dist/runtime/helpers/getIntersectionsCss.d.ts +0 -0
- package/dist/runtime/helpers/getIntersectionsCss.js +56 -0
- package/dist/runtime/helpers/getMoveEdgeInfo.d.ts +0 -0
- package/dist/runtime/helpers/getMoveEdgeInfo.js +42 -0
- package/dist/runtime/helpers/getResizeLimit.d.ts +0 -0
- package/dist/runtime/helpers/getResizeLimit.js +39 -0
- package/dist/runtime/helpers/getShapeSquareCss.d.ts +0 -0
- package/dist/runtime/helpers/getShapeSquareCss.js +17 -0
- package/dist/runtime/helpers/getSideTouching.d.ts +0 -0
- package/dist/runtime/helpers/getSideTouching.js +7 -0
- package/dist/runtime/helpers/getVisualEdgeCss.d.ts +0 -0
- package/dist/runtime/helpers/getVisualEdgeCss.js +40 -0
- package/dist/runtime/helpers/getVisualEdges.d.ts +0 -0
- package/dist/runtime/helpers/getVisualEdges.js +89 -0
- package/dist/runtime/helpers/getVisualEdgesCss.d.ts +0 -0
- package/dist/runtime/helpers/getVisualEdgesCss.js +4 -0
- package/dist/runtime/helpers/getWinAndFrameById.d.ts +0 -0
- package/dist/runtime/helpers/getWinAndFrameById.js +14 -0
- package/dist/runtime/helpers/getWinByFrameUuid.d.ts +0 -0
- package/dist/runtime/helpers/getWinByFrameUuid.js +13 -0
- package/dist/runtime/helpers/getWinById.d.ts +0 -0
- package/dist/runtime/helpers/getWinById.js +5 -0
- package/dist/runtime/helpers/getWindowConstant.d.ts +0 -0
- package/dist/runtime/helpers/getWindowConstant.js +14 -0
- package/dist/runtime/helpers/inRange.d.ts +0 -0
- package/dist/runtime/helpers/inRange.js +3 -0
- package/dist/runtime/helpers/index.d.ts +0 -0
- package/dist/runtime/helpers/index.js +62 -0
- package/dist/runtime/helpers/isEdgeEqual.d.ts +0 -0
- package/dist/runtime/helpers/isEdgeEqual.js +11 -0
- package/dist/runtime/helpers/isEdgeParallel.d.ts +0 -0
- package/dist/runtime/helpers/isEdgeParallel.js +7 -0
- package/dist/runtime/helpers/isPointEqual.d.ts +0 -0
- package/dist/runtime/helpers/isPointEqual.js +3 -0
- package/dist/runtime/helpers/isSizeAboveMin.d.ts +0 -0
- package/dist/runtime/helpers/isSizeAboveMin.js +3 -0
- package/dist/runtime/helpers/isSizeEqual.d.ts +0 -0
- package/dist/runtime/helpers/isSizeEqual.js +3 -0
- package/dist/runtime/helpers/isWindowEdge.d.ts +0 -0
- package/dist/runtime/helpers/isWindowEdge.js +7 -0
- package/dist/runtime/helpers/isWindowEdgePoint.d.ts +0 -0
- package/dist/runtime/helpers/isWindowEdgePoint.js +5 -0
- package/dist/runtime/helpers/moveEdge.d.ts +0 -0
- package/dist/runtime/helpers/moveEdge.js +8 -0
- package/dist/runtime/helpers/numberToScaledPercent.d.ts +0 -0
- package/dist/runtime/helpers/numberToScaledPercent.js +5 -0
- package/dist/runtime/helpers/numberToScaledSize.d.ts +0 -0
- package/dist/runtime/helpers/numberToScaledSize.js +19 -0
- package/dist/runtime/helpers/oppositeSide.d.ts +0 -0
- package/dist/runtime/helpers/oppositeSide.js +30 -0
- package/dist/runtime/helpers/resizeByEdge.d.ts +0 -0
- package/dist/runtime/helpers/resizeByEdge.js +29 -0
- package/dist/runtime/helpers/sideToDirection.d.ts +0 -0
- package/dist/runtime/helpers/sideToDirection.js +11 -0
- package/dist/runtime/helpers/sideToOrientation.d.ts +0 -0
- package/dist/runtime/helpers/sideToOrientation.js +10 -0
- package/dist/runtime/helpers/splitEdge.d.ts +0 -0
- package/dist/runtime/helpers/splitEdge.js +20 -0
- package/dist/runtime/helpers/toCoord.d.ts +0 -0
- package/dist/runtime/helpers/toCoord.js +10 -0
- package/dist/runtime/helpers/toId.d.ts +0 -0
- package/dist/runtime/helpers/toId.js +4 -0
- package/dist/runtime/helpers/toWindowCoord.d.ts +0 -0
- package/dist/runtime/helpers/toWindowCoord.js +14 -0
- package/dist/runtime/helpers/unionEdges.d.ts +0 -0
- package/dist/runtime/helpers/unionEdges.js +8 -0
- package/dist/runtime/helpers/updateWindowSizeWithEvent.d.ts +0 -0
- package/dist/runtime/helpers/updateWindowSizeWithEvent.js +8 -0
- package/dist/runtime/index.d.ts +0 -0
- package/dist/runtime/index.js +5 -0
- package/dist/runtime/layout/closeFrame.d.ts +0 -0
- package/dist/runtime/layout/closeFrame.js +13 -0
- package/dist/runtime/layout/closeFrames.d.ts +0 -0
- package/dist/runtime/layout/closeFrames.js +8 -0
- package/dist/runtime/layout/createSplitDecoEdge.d.ts +0 -0
- package/dist/runtime/layout/createSplitDecoEdge.js +24 -0
- package/dist/runtime/layout/createSplitDecoFromDrag.d.ts +0 -0
- package/dist/runtime/layout/createSplitDecoFromDrag.js +14 -0
- package/dist/runtime/layout/debugFrame.d.ts +0 -0
- package/dist/runtime/layout/debugFrame.js +4 -0
- package/dist/runtime/layout/findFramesTouchingEdge.d.ts +0 -0
- package/dist/runtime/layout/findFramesTouchingEdge.js +33 -0
- package/dist/runtime/layout/findSafeSplitEdge.d.ts +0 -0
- package/dist/runtime/layout/findSafeSplitEdge.js +20 -0
- package/dist/runtime/layout/findVisualEdge.d.ts +0 -0
- package/dist/runtime/layout/findVisualEdge.js +9 -0
- package/dist/runtime/layout/frameCreate.d.ts +0 -0
- package/dist/runtime/layout/frameCreate.js +13 -0
- package/dist/runtime/layout/frameSplit.d.ts +0 -0
- package/dist/runtime/layout/frameSplit.js +9 -0
- package/dist/runtime/layout/getCloseFrameInfo.d.ts +0 -0
- package/dist/runtime/layout/getCloseFrameInfo.js +103 -0
- package/dist/runtime/layout/getFrameSplitInfo.d.ts +0 -0
- package/dist/runtime/layout/getFrameSplitInfo.js +40 -0
- package/dist/runtime/layout/getFrameTo.d.ts +0 -0
- package/dist/runtime/layout/getFrameTo.js +47 -0
- package/dist/runtime/layout/index.d.ts +0 -0
- package/dist/runtime/layout/index.js +22 -0
- package/dist/runtime/layout/isPointInFrame.d.ts +0 -0
- package/dist/runtime/layout/isPointInFrame.js +4 -0
- package/dist/runtime/layout/layoutAddWindow.d.ts +0 -0
- package/dist/runtime/layout/layoutAddWindow.js +4 -0
- package/dist/runtime/layout/layoutCreate.d.ts +0 -0
- package/dist/runtime/layout/layoutCreate.js +7 -0
- package/dist/runtime/layout/layoutRemoveWindow.d.ts +0 -0
- package/dist/runtime/layout/layoutRemoveWindow.js +5 -0
- package/dist/runtime/layout/resizeFrame.d.ts +0 -0
- package/dist/runtime/layout/resizeFrame.js +69 -0
- package/dist/runtime/layout/windowAddFrame.d.ts +0 -0
- package/dist/runtime/layout/windowAddFrame.js +4 -0
- package/dist/runtime/layout/windowCreate.d.ts +0 -0
- package/dist/runtime/layout/windowCreate.js +13 -0
- package/dist/runtime/layout/windowRemoveFrame.d.ts +0 -0
- package/dist/runtime/layout/windowRemoveFrame.js +5 -0
- package/dist/runtime/layout/windowSetActiveFrame.d.ts +0 -0
- package/dist/runtime/layout/windowSetActiveFrame.js +5 -0
- package/dist/runtime/settings.d.ts +0 -0
- package/dist/runtime/settings.js +54 -0
- package/dist/runtime/types/index.d.ts +0 -0
- package/dist/runtime/types/index.js +120 -0
- package/dist/runtime/utils/KnownError.d.ts +0 -0
- package/dist/runtime/utils/KnownError.js +9 -0
- package/dist/types.d.mts +5 -0
- package/package.json +153 -0
- package/src/module.ts +43 -0
- package/src/runtime/components/LayoutDecos.vue +62 -0
- package/src/runtime/components/LayoutEdges.vue +172 -0
- package/src/runtime/components/LayoutFrame.vue +47 -0
- package/src/runtime/components/LayoutShapeSquare.vue +38 -0
- package/src/runtime/components/LayoutWindow.vue +223 -0
- package/src/runtime/composables/useFrames.ts +251 -0
- package/src/runtime/demo/App.vue +139 -0
- package/src/runtime/demo/DemoControls.vue +17 -0
- package/src/runtime/demo/README.md +1 -0
- package/src/runtime/demo/main.ts +9 -0
- package/src/runtime/demo/sharedLayoutInstance.ts +7 -0
- package/src/runtime/demo/tailwind.css +4 -0
- package/src/runtime/drag/CloseAction.ts +158 -0
- package/src/runtime/drag/DragActionHandler.ts +146 -0
- package/src/runtime/drag/DragDirectionStore.ts +63 -0
- package/src/runtime/drag/SplitAction.ts +147 -0
- package/src/runtime/drag/types.ts +107 -0
- package/src/runtime/helpers/addPointsToIntersection.ts +9 -0
- package/src/runtime/helpers/assertEdgeSorted.ts +11 -0
- package/src/runtime/helpers/assertItemIn.ts +13 -0
- package/src/runtime/helpers/assertItemNotIn.ts +10 -0
- package/src/runtime/helpers/assertLayoutHasActiveWindow.ts +9 -0
- package/src/runtime/helpers/assertValidWinAndFrame.ts +16 -0
- package/src/runtime/helpers/assertValidWinAndFrameIds.ts +9 -0
- package/src/runtime/helpers/assertWindowHasActiveFrame.ts +9 -0
- package/src/runtime/helpers/clampNumber.ts +9 -0
- package/src/runtime/helpers/cloneFrame.ts +5 -0
- package/src/runtime/helpers/cloneFrames.ts +20 -0
- package/src/runtime/helpers/containsEdge.ts +16 -0
- package/src/runtime/helpers/convertLayoutWindowToWorkspace.ts +18 -0
- package/src/runtime/helpers/copySize.ts +7 -0
- package/src/runtime/helpers/createEdge.ts +19 -0
- package/src/runtime/helpers/dirToOrientation.ts +12 -0
- package/src/runtime/helpers/dirToSide.ts +7 -0
- package/src/runtime/helpers/doEdgesOverlap.ts +25 -0
- package/src/runtime/helpers/doesEdgeContinueEdge.ts +20 -0
- package/src/runtime/helpers/edgeToPoints.ts +5 -0
- package/src/runtime/helpers/findDraggableEdge.ts +24 -0
- package/src/runtime/helpers/findFrameDraggableEdges.ts +32 -0
- package/src/runtime/helpers/frameToEdges.ts +32 -0
- package/src/runtime/helpers/frameToPoints.ts +14 -0
- package/src/runtime/helpers/getEdgeOrientation.ts +6 -0
- package/src/runtime/helpers/getEdgeSharedDirection.ts +10 -0
- package/src/runtime/helpers/getEdgeSide.ts +27 -0
- package/src/runtime/helpers/getFrameById.ts +15 -0
- package/src/runtime/helpers/getFrameConstant.ts +22 -0
- package/src/runtime/helpers/getIntersections.ts +87 -0
- package/src/runtime/helpers/getIntersectionsCss.ts +65 -0
- package/src/runtime/helpers/getMoveEdgeInfo.ts +69 -0
- package/src/runtime/helpers/getResizeLimit.ts +60 -0
- package/src/runtime/helpers/getShapeSquareCss.ts +28 -0
- package/src/runtime/helpers/getSideTouching.ts +9 -0
- package/src/runtime/helpers/getVisualEdgeCss.ts +53 -0
- package/src/runtime/helpers/getVisualEdges.ts +155 -0
- package/src/runtime/helpers/getVisualEdgesCss.ts +13 -0
- package/src/runtime/helpers/getWinAndFrameById.ts +28 -0
- package/src/runtime/helpers/getWinByFrameUuid.ts +19 -0
- package/src/runtime/helpers/getWinById.ts +12 -0
- package/src/runtime/helpers/getWindowConstant.ts +21 -0
- package/src/runtime/helpers/inRange.ts +5 -0
- package/src/runtime/helpers/index.ts +64 -0
- package/src/runtime/helpers/isEdgeEqual.ts +14 -0
- package/src/runtime/helpers/isEdgeParallel.ts +10 -0
- package/src/runtime/helpers/isPointEqual.ts +5 -0
- package/src/runtime/helpers/isSizeAboveMin.ts +8 -0
- package/src/runtime/helpers/isSizeEqual.ts +5 -0
- package/src/runtime/helpers/isWindowEdge.ts +11 -0
- package/src/runtime/helpers/isWindowEdgePoint.ts +8 -0
- package/src/runtime/helpers/moveEdge.ts +21 -0
- package/src/runtime/helpers/numberToScaledPercent.ts +19 -0
- package/src/runtime/helpers/numberToScaledSize.ts +28 -0
- package/src/runtime/helpers/oppositeSide.ts +45 -0
- package/src/runtime/helpers/resizeByEdge.ts +45 -0
- package/src/runtime/helpers/sideToDirection.ts +15 -0
- package/src/runtime/helpers/sideToOrientation.ts +12 -0
- package/src/runtime/helpers/splitEdge.ts +23 -0
- package/src/runtime/helpers/toCoord.ts +13 -0
- package/src/runtime/helpers/toId.ts +9 -0
- package/src/runtime/helpers/toWindowCoord.ts +23 -0
- package/src/runtime/helpers/unionEdges.ts +11 -0
- package/src/runtime/helpers/updateWindowSizeWithEvent.ts +10 -0
- package/src/runtime/index.ts +5 -0
- package/src/runtime/layout/closeFrame.ts +33 -0
- package/src/runtime/layout/closeFrames.ts +14 -0
- package/src/runtime/layout/createSplitDecoEdge.ts +34 -0
- package/src/runtime/layout/createSplitDecoFromDrag.ts +24 -0
- package/src/runtime/layout/debugFrame.ts +6 -0
- package/src/runtime/layout/findFramesTouchingEdge.ts +92 -0
- package/src/runtime/layout/findSafeSplitEdge.ts +39 -0
- package/src/runtime/layout/findVisualEdge.ts +11 -0
- package/src/runtime/layout/frameCreate.ts +23 -0
- package/src/runtime/layout/frameSplit.ts +31 -0
- package/src/runtime/layout/getCloseFrameInfo.ts +193 -0
- package/src/runtime/layout/getFrameSplitInfo.ts +65 -0
- package/src/runtime/layout/getFrameTo.ts +65 -0
- package/src/runtime/layout/index.ts +24 -0
- package/src/runtime/layout/isPointInFrame.ts +7 -0
- package/src/runtime/layout/layoutAddWindow.ts +6 -0
- package/src/runtime/layout/layoutCreate.ts +12 -0
- package/src/runtime/layout/layoutRemoveWindow.ts +7 -0
- package/src/runtime/layout/resizeFrame.ts +106 -0
- package/src/runtime/layout/windowAddFrame.ts +10 -0
- package/src/runtime/layout/windowCreate.ts +18 -0
- package/src/runtime/layout/windowRemoveFrame.ts +7 -0
- package/src/runtime/layout/windowSetActiveFrame.ts +7 -0
- package/src/runtime/settings.ts +63 -0
- package/src/runtime/types/index.ts +293 -0
- package/src/runtime/utils/KnownError.ts +24 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- overflow hidden is because the borders inside will make it overflow -->
|
|
3
|
+
<div :class="twMerge(
|
|
4
|
+
`window
|
|
5
|
+
relative
|
|
6
|
+
overflow-hidden
|
|
7
|
+
`,
|
|
8
|
+
isDragging && `dragging cursor-pointer`,
|
|
9
|
+
requestType && `request-${requestType}`,
|
|
10
|
+
$attrs.attrs.class
|
|
11
|
+
)"
|
|
12
|
+
ref="windowEl"
|
|
13
|
+
v-bind="{...$attrs.attrs, class: undefined}"
|
|
14
|
+
>
|
|
15
|
+
<template v-if="windowEl && win">
|
|
16
|
+
<LayoutFrameComponent :frame="frame"
|
|
17
|
+
:is-active-frame="frame.id === win.activeFrame"
|
|
18
|
+
v-for="frame of frames"
|
|
19
|
+
:key="frame.id"
|
|
20
|
+
v-bind="$attrs.frameAttrs"
|
|
21
|
+
@focus="windowSetActiveFrame(win, frame.id)"
|
|
22
|
+
>
|
|
23
|
+
<slot :name="`frame-${frame.id}`" v-bind="{frame}"/>
|
|
24
|
+
</LayoutFrameComponent>
|
|
25
|
+
<LayoutEdgesComponent
|
|
26
|
+
:win="win"
|
|
27
|
+
:active-frame="win.activeFrame ? frames[win.activeFrame] : undefined"
|
|
28
|
+
:edges="visualEdges"
|
|
29
|
+
:intersections="intersections"
|
|
30
|
+
:dragging-edge="draggingEdges.length === 1 ? draggingEdges[0] : undefined"
|
|
31
|
+
:dragging-intersection="draggingIntersection"
|
|
32
|
+
v-bind="$attrs.edgesAttrs"
|
|
33
|
+
@drag-start="dragStart"
|
|
34
|
+
/>
|
|
35
|
+
<LayoutDecosComponent
|
|
36
|
+
:frames="frames"
|
|
37
|
+
:split-decos="splitDecos"
|
|
38
|
+
:close-decos="closeDecos"
|
|
39
|
+
v-bind="$attrs.decosAttrs"
|
|
40
|
+
/>
|
|
41
|
+
<slot name="extra-decos"/>
|
|
42
|
+
</template>
|
|
43
|
+
<Teleport v-if="instructionsTeleportTo && filteredUsageInstructions.length > 0" defer :to="instructionsTeleportTo">
|
|
44
|
+
<span aria-live="polite">
|
|
45
|
+
<span
|
|
46
|
+
class="
|
|
47
|
+
after:content-['┃']
|
|
48
|
+
after:text-accent-500
|
|
49
|
+
last:after:content-none
|
|
50
|
+
after:mx-1
|
|
51
|
+
after:text-gray-500
|
|
52
|
+
"
|
|
53
|
+
v-for="instruction of filteredUsageInstructions"
|
|
54
|
+
:key="instruction"
|
|
55
|
+
>
|
|
56
|
+
{{ instruction }}
|
|
57
|
+
</span>
|
|
58
|
+
</span>
|
|
59
|
+
</Teleport>
|
|
60
|
+
</div>
|
|
61
|
+
</template>
|
|
62
|
+
<script lang="ts" setup>
|
|
63
|
+
import { useDivideAttrs } from "@witchcraft/ui/composables/useDivideAttrs"
|
|
64
|
+
import { useGlobalResizeObserver } from "@witchcraft/ui/composables/useGlobalResizeObserver"
|
|
65
|
+
import { twMerge } from "@witchcraft/ui/utils/twMerge"
|
|
66
|
+
import { computed, ref,watch } from "vue"
|
|
67
|
+
|
|
68
|
+
import LayoutDecosComponent from "./LayoutDecos.vue"
|
|
69
|
+
import LayoutEdgesComponent from "./LayoutEdges.vue"
|
|
70
|
+
import LayoutFrameComponent from "./LayoutFrame.vue"
|
|
71
|
+
|
|
72
|
+
import { useFrames } from "../composables/useFrames.js"
|
|
73
|
+
import { CloseAction } from "../drag/CloseAction"
|
|
74
|
+
import { DragActionHandler } from "../drag/DragActionHandler"
|
|
75
|
+
import { SplitAction } from "../drag/SplitAction.js"
|
|
76
|
+
import { type DragState, type IDragAction } from "../drag/types.js"
|
|
77
|
+
import { updateWindowWithEvent } from "../helpers/updateWindowSizeWithEvent.js"
|
|
78
|
+
import { windowSetActiveFrame } from "../layout/windowSetActiveFrame.js"
|
|
79
|
+
import { type CloseDeco, type LayoutWindow, type SplitDeco } from "../types/index.js"
|
|
80
|
+
|
|
81
|
+
const $attrs = useDivideAttrs(["frame", "edges", "decos"] as const)
|
|
82
|
+
|
|
83
|
+
const win = defineModel<LayoutWindow>("win", { required: true })
|
|
84
|
+
|
|
85
|
+
const props = withDefaults(defineProps<{
|
|
86
|
+
additionalDragActions?: IDragAction[]
|
|
87
|
+
splitKeyHandler?: (e: PointerEvent | KeyboardEvent, state: DragState) => boolean
|
|
88
|
+
closeKeyHandler?: (e: PointerEvent | KeyboardEvent, state: DragState) => boolean
|
|
89
|
+
usageInstructions?: Record<string, string | undefined>
|
|
90
|
+
instructionsTeleportTo: string | undefined
|
|
91
|
+
/**
|
|
92
|
+
* You might need to temporarily disable updating the window size while transitioning, depending on your layout.
|
|
93
|
+
*
|
|
94
|
+
* For example, if the component is in a flex container, during transition, there will be two components, and it will suddenly jump in size to being 1/2 the height. We can avoid this by using the known height (from win), but to do so, we can't let this component update the size while transitioning.
|
|
95
|
+
*
|
|
96
|
+
* When this is turned back on again, it will trigger an update. You can also trigger updates manually with the exposed updateWindowSize function.
|
|
97
|
+
*/
|
|
98
|
+
allowWindowSizeUpdate?: boolean
|
|
99
|
+
}>(), {
|
|
100
|
+
additionalDragActions: () => ([]),
|
|
101
|
+
splitKeyHandler: undefined,
|
|
102
|
+
closeKeyHandler: undefined,
|
|
103
|
+
usageInstructions: () => ({ }),
|
|
104
|
+
instructionTeleportTo: undefined,
|
|
105
|
+
allowWindowSizeUpdate: true
|
|
106
|
+
})
|
|
107
|
+
const emit = defineEmits<{
|
|
108
|
+
(e: "isShowingDrag", value: boolean): void
|
|
109
|
+
(e: "dragState", value: DragState): void
|
|
110
|
+
}>()
|
|
111
|
+
|
|
112
|
+
const filteredUsageInstructions = computed(() => Object.values(props.usageInstructions).filter(_ => _ !== undefined).map(_ => _))
|
|
113
|
+
|
|
114
|
+
const splitKeyHandler = props.splitKeyHandler ?? ((e: PointerEvent | KeyboardEvent, state: DragState) =>
|
|
115
|
+
e.altKey || state.isDraggingFromWindowEdge)
|
|
116
|
+
const closeKeyHandler = props.closeKeyHandler ?? ((e: PointerEvent | KeyboardEvent) => {
|
|
117
|
+
if (e.ctrlKey && e.shiftKey) {
|
|
118
|
+
return "force"
|
|
119
|
+
}
|
|
120
|
+
if (e.shiftKey) return true
|
|
121
|
+
return false
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
const windowEl = ref<HTMLElement | null>(null)
|
|
126
|
+
|
|
127
|
+
const showDragging = ref(true)
|
|
128
|
+
|
|
129
|
+
const closeDecos = ref<CloseDeco[]>([])
|
|
130
|
+
const splitDecos = ref<SplitDeco[]>([])
|
|
131
|
+
const requestType = ref<"split" | "close" | undefined | string>()
|
|
132
|
+
|
|
133
|
+
const dragActionHandler = new DragActionHandler(
|
|
134
|
+
(
|
|
135
|
+
type: "start" | "move" | "end",
|
|
136
|
+
_e: PointerEvent | KeyboardEvent | undefined,
|
|
137
|
+
state: DragState
|
|
138
|
+
) => type === "move" ? !state.isDraggingFromWindowEdge : undefined,
|
|
139
|
+
[
|
|
140
|
+
new SplitAction(
|
|
141
|
+
splitKeyHandler,
|
|
142
|
+
((decos: SplitDeco[]) => splitDecos.value = decos),
|
|
143
|
+
{
|
|
144
|
+
onStart: () => showDragging.value = false,
|
|
145
|
+
onCancel: () => showDragging.value = true,
|
|
146
|
+
}),
|
|
147
|
+
new CloseAction(
|
|
148
|
+
closeKeyHandler,
|
|
149
|
+
((decos: CloseDeco[]) => closeDecos.value = decos),
|
|
150
|
+
),
|
|
151
|
+
...props.additionalDragActions
|
|
152
|
+
],
|
|
153
|
+
{
|
|
154
|
+
onEvent: (e, cancel) => {
|
|
155
|
+
showDragging.value = true
|
|
156
|
+
if (e instanceof KeyboardEvent && e.key === "Escape") {
|
|
157
|
+
cancel()
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
onRequestChange: type => {
|
|
161
|
+
requestType.value = type
|
|
162
|
+
},
|
|
163
|
+
onEnd: () => {
|
|
164
|
+
requestType.value = undefined
|
|
165
|
+
showDragging.value = true
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
const {
|
|
171
|
+
dragStart,
|
|
172
|
+
visualEdges,
|
|
173
|
+
isDragging,
|
|
174
|
+
draggingEdges,
|
|
175
|
+
draggingIntersection,
|
|
176
|
+
frames,
|
|
177
|
+
intersections,
|
|
178
|
+
state,
|
|
179
|
+
} = useFrames(
|
|
180
|
+
win,
|
|
181
|
+
showDragging,
|
|
182
|
+
dragActionHandler,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
function getWindowOffset() {
|
|
187
|
+
const windowElRect = windowEl.value!.getBoundingClientRect()
|
|
188
|
+
return {
|
|
189
|
+
pxX: Math.floor(windowElRect.x),
|
|
190
|
+
pxY: Math.floor(windowElRect.y),
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function getWindowSize() {
|
|
194
|
+
const windowElRect = windowEl.value!.getBoundingClientRect()
|
|
195
|
+
return {
|
|
196
|
+
pxWidth: Math.floor(windowElRect.width),
|
|
197
|
+
pxHeight: Math.floor(windowElRect.height),
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function updateWindowSize() {
|
|
201
|
+
if (!props.allowWindowSizeUpdate) return
|
|
202
|
+
const newSize = { ...getWindowSize(), ...getWindowOffset() }
|
|
203
|
+
updateWindowWithEvent(win.value, newSize)
|
|
204
|
+
}
|
|
205
|
+
useGlobalResizeObserver(windowEl, updateWindowSize)
|
|
206
|
+
watch(() => props.allowWindowSizeUpdate, (newval, oldval) => {
|
|
207
|
+
if (oldval === false && newval === true) {
|
|
208
|
+
updateWindowSize()
|
|
209
|
+
}
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
watch(state, () => emit("dragState", state.value))
|
|
214
|
+
watch(showDragging, () => emit("isShowingDrag", showDragging.value))
|
|
215
|
+
|
|
216
|
+
defineExpose({
|
|
217
|
+
state,
|
|
218
|
+
win,
|
|
219
|
+
updateWindowSize,
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
</script>
|
|
223
|
+
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { debounce } from "@alanscodelog/utils/debounce"
|
|
2
|
+
import { keys } from "@alanscodelog/utils/keys"
|
|
3
|
+
import type { Ref } from "vue"
|
|
4
|
+
import { computed, onBeforeUnmount, onMounted, ref, watchEffect } from "vue"
|
|
5
|
+
|
|
6
|
+
import { DragDirectionStore } from "../drag/DragDirectionStore.js"
|
|
7
|
+
import type { DragChangeHandler, DragState } from "../drag/types.js"
|
|
8
|
+
import { cloneFrame } from "../helpers/cloneFrame.js"
|
|
9
|
+
import { getIntersections } from "../helpers/getIntersections.js"
|
|
10
|
+
import { getVisualEdges } from "../helpers/getVisualEdges.js"
|
|
11
|
+
import { isWindowEdge } from "../helpers/isWindowEdge.js"
|
|
12
|
+
import { moveEdge } from "../helpers/moveEdge.js"
|
|
13
|
+
import { toWindowCoord } from "../helpers/toWindowCoord.js"
|
|
14
|
+
import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js"
|
|
15
|
+
import { isPointInFrame } from "../layout/isPointInFrame.js"
|
|
16
|
+
import type { Direction, Edge, IntersectionEntry, LayoutFrame, LayoutWindow, Orientation, Point } from "../types/index.js"
|
|
17
|
+
|
|
18
|
+
export function useFrames(
|
|
19
|
+
win: Ref<LayoutWindow>,
|
|
20
|
+
/** Whether to show merged the moved frames while dragging. */
|
|
21
|
+
showDragging: Ref<boolean>,
|
|
22
|
+
handler: {
|
|
23
|
+
eventHandler: (e: KeyboardEvent, state: DragState, forceRecalculateEdges: () => void) => void
|
|
24
|
+
/**
|
|
25
|
+
* Called when the drag coordinates change (during any event). Should return true to allow the edges to be moved, or false to prevent it.
|
|
26
|
+
*
|
|
27
|
+
* Can be used to save some context/info to later apply safely during onDragApply.
|
|
28
|
+
*/
|
|
29
|
+
onDragChange: DragChangeHandler
|
|
30
|
+
/**
|
|
31
|
+
* Called when drag will be applied. If dragEnd was called with apply false, it will not be called.
|
|
32
|
+
* Return false to not apply the regular drag end changes (i.e. return false to reset to the position before dragging).
|
|
33
|
+
*/
|
|
34
|
+
onDragApply: ((state: DragState, forceRecalculateEdges: () => void) => boolean)
|
|
35
|
+
}
|
|
36
|
+
) {
|
|
37
|
+
const draggingEdges = ref<Edge[]>([])
|
|
38
|
+
|
|
39
|
+
// each entry corresponds to the frames touching the corresponding dragging edge
|
|
40
|
+
const touchingFrames = ref<Record<string, LayoutFrame>[]>([])
|
|
41
|
+
const allTouchingFrames = computed(() => {
|
|
42
|
+
const result: Record<string, LayoutFrame> = {}
|
|
43
|
+
for (const entry of touchingFrames.value) {
|
|
44
|
+
for (const frame of Object.values(entry)) {
|
|
45
|
+
result[frame.id] = frame
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const touchingFramesArrays = computed(() => touchingFrames.value.map(entry => Object.values(entry)))
|
|
52
|
+
|
|
53
|
+
const isDragging = ref(false)
|
|
54
|
+
const dragPoint = ref<Point | undefined>()
|
|
55
|
+
|
|
56
|
+
const dragDirections = ref<Record<Orientation, Direction | undefined>>({} as any)
|
|
57
|
+
|
|
58
|
+
const draggingIntersection = ref<IntersectionEntry | undefined>(undefined)
|
|
59
|
+
const isDraggingFromWindowEdge = ref<boolean>(false)
|
|
60
|
+
|
|
61
|
+
const frames = computed(() =>
|
|
62
|
+
isDragging.value && showDragging.value
|
|
63
|
+
? { ...win.value.frames, ...allTouchingFrames.value }
|
|
64
|
+
: win.value.frames
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
const dragHoveredFrame = computed(() => {
|
|
68
|
+
if (isDragging.value) {
|
|
69
|
+
for (const id of keys(frames.value)) {
|
|
70
|
+
if (isPointInFrame(frames.value[id], dragPoint.value!)) {
|
|
71
|
+
return frames.value[id]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return undefined
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
const visualEdges = ref<Edge[]>([])
|
|
79
|
+
const intersections = computed(() => getIntersections(visualEdges.value))
|
|
80
|
+
// avoid expensive calculation of edges when lots of frames are added/removed
|
|
81
|
+
// all at once (e.g. by clicking on some command many times in a row)
|
|
82
|
+
const debounceGetDraggableEdges = debounce((f: LayoutFrame[]) => {
|
|
83
|
+
visualEdges.value = getVisualEdges(f, { includeWindowEdges: true })
|
|
84
|
+
}, 50, {}) as any
|
|
85
|
+
|
|
86
|
+
watchEffect(() => {
|
|
87
|
+
// let request animation force recalc
|
|
88
|
+
if (isDragging.value) return
|
|
89
|
+
// otherwise use more performant debounced version
|
|
90
|
+
debounceGetDraggableEdges(Object.values(frames.value))
|
|
91
|
+
})
|
|
92
|
+
function forceRecalculateEdges(): void {
|
|
93
|
+
visualEdges.value = getVisualEdges(Object.values(frames.value), { includeWindowEdges: true })
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const dragDirStore = new DragDirectionStore({
|
|
97
|
+
onUpdate: dir => dragDirections.value = dir
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const state = computed(() => ({
|
|
101
|
+
dragDirections: dragDirections.value,
|
|
102
|
+
dragPoint: dragPoint.value,
|
|
103
|
+
isDragging: isDragging.value,
|
|
104
|
+
draggingEdges: draggingEdges.value,
|
|
105
|
+
draggingIntersection: draggingIntersection.value,
|
|
106
|
+
visualEdges: visualEdges.value,
|
|
107
|
+
touchingFrames: touchingFrames.value,
|
|
108
|
+
touchingFramesArrays: touchingFramesArrays.value,
|
|
109
|
+
frames: frames.value,
|
|
110
|
+
dragHoveredFrame: dragHoveredFrame.value,
|
|
111
|
+
intersections: intersections.value,
|
|
112
|
+
isDraggingFromWindowEdge: isDraggingFromWindowEdge.value,
|
|
113
|
+
win: win.value
|
|
114
|
+
} satisfies DragState))
|
|
115
|
+
|
|
116
|
+
let controller: AbortController
|
|
117
|
+
|
|
118
|
+
function resetState(): void {
|
|
119
|
+
draggingEdges.value = []
|
|
120
|
+
draggingIntersection.value = undefined
|
|
121
|
+
isDragging.value = false
|
|
122
|
+
dragPoint.value = undefined
|
|
123
|
+
touchingFrames.value = []
|
|
124
|
+
dragDirStore.reset()
|
|
125
|
+
forceRecalculateEdges()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function dragStart(e: PointerEvent, { edge, intersection }: { edge?: Edge, intersection?: IntersectionEntry }): void {
|
|
129
|
+
controller = new AbortController()
|
|
130
|
+
controller.signal.addEventListener("abort", () => resetState())
|
|
131
|
+
|
|
132
|
+
e.preventDefault()
|
|
133
|
+
window.addEventListener("pointermove", dragMove, { signal: controller.signal })
|
|
134
|
+
window.addEventListener("pointerup", dragEnd, { signal: controller.signal })
|
|
135
|
+
|
|
136
|
+
const point = toWindowCoord(win.value, e)
|
|
137
|
+
dragPoint.value = point
|
|
138
|
+
|
|
139
|
+
isDragging.value = true
|
|
140
|
+
|
|
141
|
+
draggingIntersection.value = intersection
|
|
142
|
+
|
|
143
|
+
draggingEdges.value = edge
|
|
144
|
+
? [edge]
|
|
145
|
+
: [
|
|
146
|
+
...(draggingIntersection.value?.sharedEdges.horizontal ?? []),
|
|
147
|
+
...(draggingIntersection.value?.sharedEdges.vertical ?? [])
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
dragDirStore.update(point)
|
|
151
|
+
isDraggingFromWindowEdge.value = draggingEdges.value.some(_ => isWindowEdge(_))
|
|
152
|
+
|
|
153
|
+
const framesArray = Object.values(win.value.frames)
|
|
154
|
+
|
|
155
|
+
touchingFrames.value = []
|
|
156
|
+
// all frames in touchingFrames must be clones
|
|
157
|
+
// BUT they must be the same clone even if they are referenced by multiple dragging edges
|
|
158
|
+
const clones = new Map<string, LayoutFrame>()
|
|
159
|
+
for (let i = 0; i < draggingEdges.value.length; i++) {
|
|
160
|
+
const draggingEdge = draggingEdges.value[i]
|
|
161
|
+
touchingFrames.value[i] = {}
|
|
162
|
+
for (const { frame } of findFramesTouchingEdge(draggingEdge, framesArray)) {
|
|
163
|
+
if (!clones.has(frame.id)) {
|
|
164
|
+
const clone = cloneFrame(frame)
|
|
165
|
+
touchingFrames.value[i][frame.id] = clone
|
|
166
|
+
clones.set(frame.id, clone)
|
|
167
|
+
} else {
|
|
168
|
+
touchingFrames.value[i][frame.id] = clones.get(frame.id)!
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
handler.onDragChange("start", e, state.value, forceRecalculateEdges, cancel)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function dragMove(e: PointerEvent): void {
|
|
177
|
+
e.preventDefault()
|
|
178
|
+
const point = toWindowCoord(win.value, e)
|
|
179
|
+
const didChange = dragDirStore.update(point)
|
|
180
|
+
dragPoint.value = point
|
|
181
|
+
if (!didChange) return
|
|
182
|
+
const allowed = handler.onDragChange("move", e, state.value, forceRecalculateEdges, cancel)
|
|
183
|
+
|
|
184
|
+
if (!allowed) return
|
|
185
|
+
requestAnimationFrame(() => {
|
|
186
|
+
for (let i = 0; i < draggingEdges.value.length; i++) {
|
|
187
|
+
const draggingEdge = draggingEdges.value[i]
|
|
188
|
+
if (draggingEdge) {
|
|
189
|
+
moveEdge(touchingFramesArrays.value[i], draggingEdge, point)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
forceRecalculateEdges()
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function dragEnd(e?: PointerEvent, { apply = true }: { apply?: boolean } = {}): void {
|
|
197
|
+
if (e) {
|
|
198
|
+
const point = toWindowCoord(win.value, e)
|
|
199
|
+
dragPoint.value = point
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const doApply = apply && handler.onDragApply(state.value, forceRecalculateEdges)
|
|
203
|
+
if (doApply) {
|
|
204
|
+
for (const frame of touchingFramesArrays.value.flat()) {
|
|
205
|
+
win!.value.frames[frame.id] = frame
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
handler.onDragChange("end", e, state.value, forceRecalculateEdges, cancel)
|
|
210
|
+
|
|
211
|
+
// this can get called from elsewhere
|
|
212
|
+
// also takes care of cleanup
|
|
213
|
+
controller?.abort()
|
|
214
|
+
}
|
|
215
|
+
function cancel(): void {
|
|
216
|
+
dragEnd(undefined, { apply: false })
|
|
217
|
+
}
|
|
218
|
+
const keydownController = new AbortController()
|
|
219
|
+
const wrappedKeydownHandler = (e: KeyboardEvent): void => {
|
|
220
|
+
handler.eventHandler(e, state.value, forceRecalculateEdges)
|
|
221
|
+
}
|
|
222
|
+
onMounted(() => {
|
|
223
|
+
window.addEventListener("keydown", wrappedKeydownHandler, { signal: keydownController.signal })
|
|
224
|
+
window.addEventListener("keyup", wrappedKeydownHandler, { signal: keydownController.signal })
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
onBeforeUnmount(() => {
|
|
228
|
+
controller?.abort()
|
|
229
|
+
keydownController?.abort()
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
dragStart,
|
|
234
|
+
dragEnd,
|
|
235
|
+
cancel,
|
|
236
|
+
dragDirections,
|
|
237
|
+
dragPoint,
|
|
238
|
+
isDragging,
|
|
239
|
+
draggingEdges,
|
|
240
|
+
draggingIntersection,
|
|
241
|
+
visualEdges,
|
|
242
|
+
touchingFrames,
|
|
243
|
+
touchingFramesArrays,
|
|
244
|
+
frames,
|
|
245
|
+
dragHoveredFrame,
|
|
246
|
+
intersections,
|
|
247
|
+
isDraggingFromWindowEdge,
|
|
248
|
+
forceRecalculateEdges,
|
|
249
|
+
state
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<WRoot class="gap-2 p-2">
|
|
3
|
+
<DemoControls
|
|
4
|
+
:frames="frames!"
|
|
5
|
+
/>
|
|
6
|
+
<LayoutWindow v-if="win"
|
|
7
|
+
class="
|
|
8
|
+
flex-1 w-full
|
|
9
|
+
border-1
|
|
10
|
+
border-neutral-300
|
|
11
|
+
dark:border-neutral-700
|
|
12
|
+
rounded-md
|
|
13
|
+
flex-1
|
|
14
|
+
self-stretch
|
|
15
|
+
[&_.frame]:flex
|
|
16
|
+
[&_.frame]:flex-col
|
|
17
|
+
[&_.frame]:outline-hidden
|
|
18
|
+
[&_.active-frame-edge]:rounded-md
|
|
19
|
+
[&_.active-frame-edge]:border-none
|
|
20
|
+
[&_.drag-edge:hover+.edge]:bg-accent-500/20
|
|
21
|
+
[&_.grabbed-edge]:bg-accent-500
|
|
22
|
+
[&.request-split_.grabbed-edge]:hidden
|
|
23
|
+
[&.request-split_.drag-edge]:hidden
|
|
24
|
+
[&_.deco-split-new-frame]:rounded-md
|
|
25
|
+
[&_.deco-close-frame]:rounded-md
|
|
26
|
+
[&_.deco-close-frame]:bg-orange-500/50
|
|
27
|
+
"
|
|
28
|
+
:usage-instructions="usageInstructions"
|
|
29
|
+
instructions-teleport-to="#status-bar"
|
|
30
|
+
v-model:win="win"
|
|
31
|
+
@is-showing-drag="isShowingDrag = $event"
|
|
32
|
+
@drag-state="dragState = $event"
|
|
33
|
+
>
|
|
34
|
+
<template #[`frame-${f.id}`] v-for="f in frames" :key="f.id">
|
|
35
|
+
<div
|
|
36
|
+
:data-is-active="win.activeFrame === f.id"
|
|
37
|
+
:class="twMerge(`
|
|
38
|
+
border-2
|
|
39
|
+
border-neutral-500
|
|
40
|
+
h-full
|
|
41
|
+
rounded-md
|
|
42
|
+
overflow-auto
|
|
43
|
+
`,
|
|
44
|
+
win.activeFrame === f.id && `border-blue-500`
|
|
45
|
+
)"
|
|
46
|
+
@click="win.activeFrame=f.id"
|
|
47
|
+
>
|
|
48
|
+
<!--
|
|
49
|
+
Avoid placing the padding on the first div in the frame.
|
|
50
|
+
Set it on the first child instead, so that the frame can shrink as small as possible.
|
|
51
|
+
Too big a border can also be a problem, but usually it's small enough that it's beneath the min frame width/height allowed.
|
|
52
|
+
-->
|
|
53
|
+
<div class="p-2"> {{ debugFrame(f) }} </div>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
</LayoutWindow>
|
|
57
|
+
</Wroot>
|
|
58
|
+
</template>
|
|
59
|
+
<script lang="ts" setup>
|
|
60
|
+
import { keys } from "@alanscodelog/utils/keys"
|
|
61
|
+
// playground not resolving???
|
|
62
|
+
// todo this breaks the non-playground build
|
|
63
|
+
import WRoot from "@witchcraft/ui/components/LibRoot"
|
|
64
|
+
import { twMerge } from "@witchcraft/ui/utils/twMerge"
|
|
65
|
+
import { computed, onBeforeMount, ref } from "vue"
|
|
66
|
+
|
|
67
|
+
import DemoControls from "./DemoControls.vue"
|
|
68
|
+
import { app } from "./sharedLayoutInstance.js"
|
|
69
|
+
|
|
70
|
+
import LayoutWindow from "../components/LayoutWindow.vue"
|
|
71
|
+
import type { DragState } from "../drag/types.js"
|
|
72
|
+
import { debugFrame } from "../layout/debugFrame.js"
|
|
73
|
+
import {
|
|
74
|
+
frameCreate,
|
|
75
|
+
layoutAddWindow,
|
|
76
|
+
windowAddFrame,
|
|
77
|
+
windowCreate,
|
|
78
|
+
} from "../layout/index.js"
|
|
79
|
+
import { getMaxInt } from "../settings.js"
|
|
80
|
+
import { type Layout, type Pos, type Size } from "../types/index.js"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
const winId = ref<string | undefined>(undefined)
|
|
84
|
+
const win = computed(() => winId.value !== undefined ? app.layout.windows[winId.value] : undefined)
|
|
85
|
+
|
|
86
|
+
const frames = computed(() => {
|
|
87
|
+
if (!win.value) return
|
|
88
|
+
return Object.values(win.value.frames)
|
|
89
|
+
})
|
|
90
|
+
onBeforeMount(() => {
|
|
91
|
+
layoutInitialize(app.layout)
|
|
92
|
+
winId.value = keys(app.layout.windows)[0]
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const isDragging = ref(false)
|
|
96
|
+
function layoutInitialize(layout: Layout, { defaultPos, defaultSize }: {
|
|
97
|
+
defaultPos: Pos
|
|
98
|
+
defaultSize: Size
|
|
99
|
+
} = {
|
|
100
|
+
defaultPos: { x: 0, y: 0 },
|
|
101
|
+
defaultSize: { width: 0, height: 0 },
|
|
102
|
+
}) {
|
|
103
|
+
const w = layoutAddWindow(
|
|
104
|
+
layout,
|
|
105
|
+
windowCreate({
|
|
106
|
+
...defaultPos,
|
|
107
|
+
...defaultSize,
|
|
108
|
+
frames: {},
|
|
109
|
+
})
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
layout.activeWindow = w.id
|
|
113
|
+
const max = getMaxInt()
|
|
114
|
+
const frame = windowAddFrame(w, frameCreate({
|
|
115
|
+
x: 0,
|
|
116
|
+
y: 0,
|
|
117
|
+
width: max,
|
|
118
|
+
height: max,
|
|
119
|
+
}))
|
|
120
|
+
w.activeFrame = frame.id
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// whether layout window is showing the edge beneath the mouse
|
|
124
|
+
// as determined by the DragActionHandler in LayoutWindow
|
|
125
|
+
const isShowingDrag = ref(false)
|
|
126
|
+
// drag state as returned by useFrames in LayoutWindow
|
|
127
|
+
const dragState = ref<DragState | undefined>(undefined)
|
|
128
|
+
|
|
129
|
+
const usageInstructions = computed(() => ({
|
|
130
|
+
// names are arbitrary and don't mean anything, they just make things easier
|
|
131
|
+
// if a key is undefined, it's ignored
|
|
132
|
+
none: !dragState.value?.isDragging ? "Drag from an edge to create a new frame." : undefined,
|
|
133
|
+
split: dragState.value?.isDragging ? "Hold Alt to Split" : undefined,
|
|
134
|
+
close: dragState.value?.isDragging ? "Shift+Drag to Close" : undefined,
|
|
135
|
+
forceClose: dragState.value?.isDragging ? "Ctrl+Shift+Drag to Force Close" : undefined
|
|
136
|
+
}))
|
|
137
|
+
|
|
138
|
+
</script>
|
|
139
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="border-2 border-neutral-500 p-2 rounded-md flex">
|
|
3
|
+
<div class="">Instruction/status bar:</div>
|
|
4
|
+
<div id="status-bar" class="px-2 flex-1 overflow-x-auto scrollbar-hidden"/>
|
|
5
|
+
<WDarkModeSwitcher :show-label="false"/>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import WDarkModeSwitcher from "@witchcraft/ui/components/LibDarkModeSwitcher"
|
|
10
|
+
|
|
11
|
+
import type { LayoutFrame } from "../types/index.js"
|
|
12
|
+
|
|
13
|
+
defineProps<{
|
|
14
|
+
frames: LayoutFrame[]
|
|
15
|
+
}>()
|
|
16
|
+
|
|
17
|
+
</script>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
This is structured like this so we can check the demo is both buildable from nuxt and vite.
|