From f1c3d50930c288b2d4d0aa33a373aecefce8b7c5 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Wed, 22 Nov 2023 20:50:55 +0000 Subject: [PATCH] functioning resize --- .../_components/ScreenList/index.svelte | 90 +++++-------- .../_components/ScreenList/resizable.js | 121 ++++++++++++++++++ 2 files changed, 150 insertions(+), 61 deletions(-) create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte index ef5911c0f8..a7d56e047a 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte @@ -9,51 +9,42 @@ import NavItem from "components/common/NavItem.svelte" import RoleIndicator from "./RoleIndicator.svelte" import DropdownMenu from "./DropdownMenu.svelte" - import { onMount, tick } from "svelte" import { goto } from "@roxi/routify" + import { getVerticalResizeActions } from './resizable'; + import { tick } from "svelte" - let search = false + const [resizable, resizableHandle] = getVerticalResizeActions(); + + let searching = false let resizing = false let searchValue = "" let searchInput let container let screensContainer let scrolling = false - let previousHeight = null - let dragOffset $: filteredScreens = getFilteredScreens($sortedScreens, searchValue) - const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) - const openSearch = async () => { - search = true + searching = true await tick() searchInput.focus() screensContainer.scroll({ top: 0, behavior: "smooth" }) - previousHeight = $screensHeight - $screensHeight = "calc(100% + 1px)" } const closeSearch = async () => { - if (previousHeight) { - // Restore previous height and wait for animation - $screensHeight = previousHeight - previousHeight = null - await sleep(300) - } - search = false + searching = false searchValue = "" } - const getFilteredScreens = (screens, search) => { + const getFilteredScreens = (screens, searchValue) => { return screens.filter(screen => { - return !search || screen.routing.route.includes(search) + return !searchValue || screen.routing.route.includes(searchValue) }) } const handleAddButton = () => { - if (search) { + if (searching) { closeSearch() } else { $goto("../new") @@ -70,67 +61,35 @@ scrolling = e.target.scrollTop !== 0 } - const startResizing = e => { - // Reset the height store to match the true height - $screensHeight = `${container.getBoundingClientRect().height}px` - - // Store an offset to easily compute new height when moving the mouse - dragOffset = parseInt($screensHeight) - e.clientY - - // Add event listeners - resizing = true - document.addEventListener("mousemove", resize) - document.addEventListener("mouseup", stopResizing) - } - - const resize = e => { - // Prevent negative heights as this screws with layout - const newHeight = Math.max(0, e.clientY + dragOffset) - if (newHeight == null || isNaN(newHeight)) { - return - } - $screensHeight = `${newHeight}px` - } - - const stopResizing = () => { - resizing = false - document.removeEventListener("mousemove", resize) - } - - onMount(() => { - // Ensure we aren't stuck at 100% height from leaving while searching - if ($screensHeight == null || isNaN(parseInt($screensHeight))) { - $screensHeight = "210px" - } - })
-
+
Screens
-
+
@@ -164,8 +123,10 @@
screensHeight.set("210px")} />
@@ -177,10 +138,11 @@ min-height: 147px; max-height: calc(100% - 147px); position: relative; - } - .screens.search { transition: height 300ms ease-out; + } + .screens.searching { max-height: none; + height: 100% !important; } .screens.resizing { user-select: none; @@ -219,7 +181,7 @@ .input::placeholder { color: var(--spectrum-global-color-gray-600); } - .screens.search input { + .screens.searching input { display: block; } @@ -305,4 +267,10 @@ .divider:hover:after { background: var(--spectrum-global-color-gray-300); } + .divider.disabled { + cursor: auto; + } + .divider.disabled:after { + background: var(--spectrum-global-color-gray-200); + } diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js new file mode 100644 index 0000000000..c3bccf024d --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/resizable.js @@ -0,0 +1,121 @@ +export const getHorizontalResizeActions = (initialValue, setValue = () => {}) => { + let element = null; + + const elementAction = (node) => { + element = node; + + if (initialValue != null) { + element.style.height = `${initialValue}px` + } + + return { + destroy() { + element = null; + } + } + } + + const dragHandleAction = (node) => { + let startWidth = null; + let startPosition = null; + + const handleMouseMove = (e) => { + const change = e.pageX - startPosition; + element.style.width = `${startWidth + change}px` + } + + const handleMouseUp = () => { + window.removeEventListener("mousemove", handleMouseMove); + window.removeEventListener("mouseup", handleMouseUp); + element.style.removeProperty('transition'); // remove temporary transition override + setValue(element.clientHeight); + } + + const handleMouseDown = (e) => { + if (e.target.hasAttribute("disabled") && e.target.getAttribute("disabled") !== "false") { + return; + } + + element.style.transition = "width 0ms"; // temporarily override any width transitions + startWidth = element.clientWidth; + startPosition = e.pageX; + + window.addEventListener("mousemove", handleMouseMove); + window.addEventListener("mouseup", handleMouseUp); + }; + + node.addEventListener("mousedown", handleMouseDown); + + return { + destroy() { + node.removeEventListener("mousedown", handleMouseDown); + } + } + } + + return [ + elementAction, + dragHandleAction + ] +}; + +export const getVerticalResizeActions = (initialValue, setValue = () => {}) => { + let element = null; + + const elementAction = (node) => { + element = node; + + if (initialValue != null) { + element.style.height = `${initialValue}px` + } + + return { + destroy() { + element = null; + } + } + } + + const dragHandleAction = (node) => { + let startHeight = null; + let startPosition = null; + + const handleMouseMove = (e) => { + const change = e.pageY - startPosition; + element.style.height = `${startHeight + change}px` + } + + const handleMouseUp = () => { + window.removeEventListener("mousemove", handleMouseMove); + window.removeEventListener("mouseup", handleMouseUp); + element.style.removeProperty('transition'); // remove temporary transition override + setValue(element.clientHeight); + } + + const handleMouseDown = (e) => { + if (e.target.hasAttribute("disabled") && e.target.getAttribute("disabled") !== "false") { + return; + } + + element.style.transition = "height 0ms"; // temporarily override any height transitions + startHeight = element.clientHeight; + startPosition = e.pageY; + + window.addEventListener("mousemove", handleMouseMove); + window.addEventListener("mouseup", handleMouseUp); + }; + + node.addEventListener("mousedown", handleMouseDown); + + return { + destroy() { + node.removeEventListener("mousedown", handleMouseDown); + } + } + } + + return [ + elementAction, + dragHandleAction + ] +};