From 05886d0f9702c951462c1b476ad69cad271b769c Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Thu, 26 Feb 2026 15:51:38 +0000 Subject: [PATCH 1/6] Fix mobile color picker drag bounds --- ui/colourpicker.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ui/colourpicker.js b/ui/colourpicker.js index 7969872f..71246c68 100644 --- a/ui/colourpicker.js +++ b/ui/colourpicker.js @@ -897,8 +897,14 @@ class CustomColorPicker { const parentRect = parent.getBoundingClientRect(); const pickerRect = this.container.getBoundingClientRect(); - const newLeft = Math.max(0, Math.min(startLeft + dx, parentRect.width - pickerRect.width)); - const newTop = Math.max(0, Math.min(startTop + dy, parentRect.height - pickerRect.height)); + const maxLeft = Math.max(0, parentRect.width - pickerRect.width); + const maxTopInViewport = Math.max( + 0, + window.innerHeight - parentRect.top - pickerRect.height, + ); + + const newLeft = Math.max(0, Math.min(startLeft + dx, maxLeft)); + const newTop = Math.max(0, Math.min(startTop + dy, maxTopInViewport)); this.container.style.left = `${newLeft}px`; this.container.style.top = `${newTop}px`; From a393793101daf8f89dd3c2f005c59eb0ecf9a6ea Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Thu, 26 Feb 2026 16:07:45 +0000 Subject: [PATCH 2/6] Allow mobile color picker to drag below gizmos --- ui/colourpicker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/colourpicker.js b/ui/colourpicker.js index 71246c68..021c6afc 100644 --- a/ui/colourpicker.js +++ b/ui/colourpicker.js @@ -898,9 +898,10 @@ class CustomColorPicker { const pickerRect = this.container.getBoundingClientRect(); const maxLeft = Math.max(0, parentRect.width - pickerRect.width); + const dragHandleHeight = Math.max(1, handle.offsetHeight || 24); const maxTopInViewport = Math.max( 0, - window.innerHeight - parentRect.top - pickerRect.height, + window.innerHeight - parentRect.top - dragHandleHeight, ); const newLeft = Math.max(0, Math.min(startLeft + dx, maxLeft)); From 1d5056e82c7dd7975f0aa3468c92c44b4f1f2539 Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Thu, 26 Feb 2026 16:20:27 +0000 Subject: [PATCH 3/6] Improve mobile touch dragging for color picker --- ui/colourpicker.css | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/colourpicker.css b/ui/colourpicker.css index 0aebea8e..c26daff2 100644 --- a/ui/colourpicker.css +++ b/ui/colourpicker.css @@ -30,6 +30,7 @@ border-radius: 4px 4px 0 0; flex-shrink: 0; user-select: none; + touch-action: none; } .color-picker-drag-handle:hover { From 52dbf31a13743af1fb8846290ff8141af27df229 Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Thu, 26 Feb 2026 16:28:56 +0000 Subject: [PATCH 4/6] Adjust mobile color picker initial position below gizmos --- ui/colourpicker.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ui/colourpicker.js b/ui/colourpicker.js index 021c6afc..f4eeac21 100644 --- a/ui/colourpicker.js +++ b/ui/colourpicker.js @@ -1863,11 +1863,23 @@ class CustomColorPicker { this.container.style.maxWidth = "none"; this.container.style.marginLeft = "10px"; this.container.style.marginRight = "10px"; - const topPosition = Math.max(10, buttonRect.top - canvasRect.top - 200); + const pickerHeight = 250; const bottomBarHeight = 40; const maxTop = canvasRect.height - pickerHeight - bottomBarHeight; - this.container.style.top = `${Math.min(topPosition, Math.max(10, maxTop))}px`; + const bottomAlignedTop = Math.max(10, maxTop); + + const gizmoButtons = document.getElementById("gizmoButtons"); + const gizmosVisible = + gizmoButtons && + getComputedStyle(gizmoButtons).display !== "none" && + getComputedStyle(gizmoButtons).visibility !== "hidden"; + const gizmoRect = gizmosVisible + ? gizmoButtons.getBoundingClientRect() + : buttonRect; + const belowGizmosTop = Math.max(10, gizmoRect.bottom - canvasRect.top + 8); + + this.container.style.top = `${Math.min(belowGizmosTop, bottomAlignedTop)}px`; } else { this.container.style.left = `${buttonRect.left - canvasRect.left}px`; this.container.style.top = `${buttonRect.top - canvasRect.top - 180}px`; From 1d477d7d39b057e4a13ec46780f03af1ed30b7d6 Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Thu, 26 Feb 2026 16:36:22 +0000 Subject: [PATCH 5/6] Fix mobile picker start position fit check --- ui/colourpicker.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ui/colourpicker.js b/ui/colourpicker.js index f4eeac21..a99878c3 100644 --- a/ui/colourpicker.js +++ b/ui/colourpicker.js @@ -1864,9 +1864,11 @@ class CustomColorPicker { this.container.style.marginLeft = "10px"; this.container.style.marginRight = "10px"; - const pickerHeight = 250; + const content = this.container.querySelector(".color-picker-content"); + const measuredPickerHeight = + content?.getBoundingClientRect().height || this.container.offsetHeight || 250; const bottomBarHeight = 40; - const maxTop = canvasRect.height - pickerHeight - bottomBarHeight; + const maxTop = canvasRect.height - measuredPickerHeight - bottomBarHeight; const bottomAlignedTop = Math.max(10, maxTop); const gizmoButtons = document.getElementById("gizmoButtons"); @@ -1879,7 +1881,9 @@ class CustomColorPicker { : buttonRect; const belowGizmosTop = Math.max(10, gizmoRect.bottom - canvasRect.top + 8); - this.container.style.top = `${Math.min(belowGizmosTop, bottomAlignedTop)}px`; + const topPosition = + belowGizmosTop <= bottomAlignedTop ? belowGizmosTop : bottomAlignedTop; + this.container.style.top = `${topPosition}px`; } else { this.container.style.left = `${buttonRect.left - canvasRect.left}px`; this.container.style.top = `${buttonRect.top - canvasRect.top - 180}px`; From 0ac2ac4aa3a91702e2671052e858726330405a56 Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Thu, 26 Feb 2026 16:49:06 +0000 Subject: [PATCH 6/6] Apply gizmo/bottom start positioning on all screen sizes --- ui/colourpicker.js | 58 ++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/ui/colourpicker.js b/ui/colourpicker.js index a99878c3..4ed83d9d 100644 --- a/ui/colourpicker.js +++ b/ui/colourpicker.js @@ -1863,51 +1863,37 @@ class CustomColorPicker { this.container.style.maxWidth = "none"; this.container.style.marginLeft = "10px"; this.container.style.marginRight = "10px"; - - const content = this.container.querySelector(".color-picker-content"); - const measuredPickerHeight = - content?.getBoundingClientRect().height || this.container.offsetHeight || 250; - const bottomBarHeight = 40; - const maxTop = canvasRect.height - measuredPickerHeight - bottomBarHeight; - const bottomAlignedTop = Math.max(10, maxTop); - - const gizmoButtons = document.getElementById("gizmoButtons"); - const gizmosVisible = - gizmoButtons && - getComputedStyle(gizmoButtons).display !== "none" && - getComputedStyle(gizmoButtons).visibility !== "hidden"; - const gizmoRect = gizmosVisible - ? gizmoButtons.getBoundingClientRect() - : buttonRect; - const belowGizmosTop = Math.max(10, gizmoRect.bottom - canvasRect.top + 8); - - const topPosition = - belowGizmosTop <= bottomAlignedTop ? belowGizmosTop : bottomAlignedTop; - this.container.style.top = `${topPosition}px`; } else { this.container.style.left = `${buttonRect.left - canvasRect.left}px`; - this.container.style.top = `${buttonRect.top - canvasRect.top - 180}px`; this.container.style.width = "360px"; this.container.style.right = "auto"; const containerWidth = 360; - if ( - buttonRect.left - canvasRect.left + containerWidth > - canvasRect.width - ) { + if (buttonRect.left - canvasRect.left + containerWidth > canvasRect.width) { this.container.style.left = `${canvasRect.width - containerWidth - 10}px`; } - if (buttonRect.top - canvasRect.top - 180 < 10) { - this.container.style.top = "10px"; - } - const pickerHeight = 250; - const bottomBarHeight = 40; - const maxTop = canvasRect.height - pickerHeight - bottomBarHeight; - const currentTop = parseInt(this.container.style.top, 10); - if (currentTop > maxTop) { - this.container.style.top = `${Math.max(10, maxTop)}px`; - } } + + const content = this.container.querySelector(".color-picker-content"); + const measuredPickerHeight = + content?.getBoundingClientRect().height || this.container.offsetHeight || 250; + const bottomBarHeight = 40; + const maxTop = canvasRect.height - measuredPickerHeight - bottomBarHeight; + const bottomAlignedTop = Math.max(10, maxTop); + + const gizmoButtons = document.getElementById("gizmoButtons"); + const gizmosVisible = + gizmoButtons && + getComputedStyle(gizmoButtons).display !== "none" && + getComputedStyle(gizmoButtons).visibility !== "hidden"; + const gizmoRect = gizmosVisible + ? gizmoButtons.getBoundingClientRect() + : buttonRect; + const belowGizmosTop = Math.max(10, gizmoRect.bottom - canvasRect.top + 8); + + const topPosition = + belowGizmosTop <= bottomAlignedTop ? belowGizmosTop : bottomAlignedTop; + this.container.style.top = `${topPosition}px`; } // After visible: size canvases, pick a usable start color, then draw & place handles