From af0783d8ffc946212e3efd352cf864e0f1b3aacb Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Thu, 16 Jan 2025 13:54:42 -0600 Subject: [PATCH 1/4] Fix divider drag jankiness --- app/assets/stylesheets/bubbles.css | 28 +++++++++++-------- .../controllers/divider_controller.js | 21 ++++++++++---- app/views/bubbles/index.html.erb | 3 +- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/app/assets/stylesheets/bubbles.css b/app/assets/stylesheets/bubbles.css index fcd1e2420..0440a40d7 100644 --- a/app/assets/stylesheets/bubbles.css +++ b/app/assets/stylesheets/bubbles.css @@ -366,18 +366,24 @@ text-decoration: none; } - li { - border-radius: 0.6em; - list-style: none; - padding: 0.5em var(--inline-space); - position: relative; - transition: background-color 200ms ease-out; + ul { + li { + border-radius: 0.6em; + list-style: none; + padding: 0.5em var(--inline-space); + position: relative; + transition: background-color 200ms ease-out; + } - @media (hover: hover) { - &:hover { - background-color: color(from var(--bubble-color) srgb r g b / 0.15); - border: 0; - border-radius: 0.6em; + &:not(.dragging) { + li { + @media (hover: hover) { + &:hover { + background-color: color(from var(--bubble-color) srgb r g b / 0.15); + border: 0; + border-radius: 0.6em; + } + } } } } diff --git a/app/javascript/controllers/divider_controller.js b/app/javascript/controllers/divider_controller.js index 847563d8f..0047d252c 100644 --- a/app/javascript/controllers/divider_controller.js +++ b/app/javascript/controllers/divider_controller.js @@ -5,7 +5,7 @@ const DIVIDER_ITEM_NODE_NAME = "LI" export default class extends Controller { static targets = [ "divider", "dragImage", "count" ] - static classes = [ "installed" ] + static classes = [ "installed", "dragging" ] static values = { startCount: Number, maxCount: Number } connect() { @@ -22,6 +22,7 @@ export default class extends Controller { event.dataTransfer.dropEffect = "move" event.dataTransfer.setData(MOVE_ITEM_DATA_TYPE, event.target) event.dataTransfer.setDragImage(this.dragImageTarget, 0, 0) + this.element.classList.add(this.draggingClass) } } @@ -31,14 +32,22 @@ export default class extends Controller { } } - moveDivider({ target }) { - if (target.nodeName == DIVIDER_ITEM_NODE_NAME) { - this.#moveDividerTo(this.#items.indexOf(target)) + moveDivider(event) { + if (event.target.nodeName == DIVIDER_ITEM_NODE_NAME) { + const rect = this.dividerTarget.getBoundingClientRect() + const distanceToTop = Math.abs(event.clientY - rect.top) + const distanceToBottom = Math.abs(event.clientY - (rect.top + rect.height)) + const distanceToNearestEdge = Math.min(distanceToTop, distanceToBottom) + const distancePercentage = (distanceToNearestEdge / rect.height) * 100 + + if (distancePercentage > 50) { + this.#moveDividerTo(this.#items.indexOf(event.target)) + } } } - persist() { - // TODO + drop() { + this.element.classList.remove(this.draggingClass) } #moveDividerTo(index) { diff --git a/app/views/bubbles/index.html.erb b/app/views/bubbles/index.html.erb index f7255893a..5dff555d4 100644 --- a/app/views/bubbles/index.html.erb +++ b/app/views/bubbles/index.html.erb @@ -39,7 +39,8 @@ data-divider-start-count-value="10" data-divider-max-count-value="10" data-divider-installed-class="bubbles-list__divider--installed" - data-action="turbo:morph@document->divider#install dragstart->divider#configureDrag dragenter->divider#acceptDrop dragover->divider#acceptDrop dragover->divider#moveDivider drop->divider#persist"> + data-divider-dragging-class="dragging" + data-action="turbo:morph@document->divider#install dragstart->divider#configureDrag dragenter->divider#acceptDrop dragover->divider#acceptDrop dragover->divider#moveDivider drop->divider#drop"> <%= render partial: "bubbles/list/bubble", collection: @bubbles, cached: true %> <%= render "bubbles/list/divider", filter: @filter %> From dc6da76b38e76e7255ea18c4c5a0652d56aafe50 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Thu, 16 Jan 2025 14:01:25 -0600 Subject: [PATCH 2/4] Simplify overlap logic --- app/javascript/controllers/divider_controller.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/javascript/controllers/divider_controller.js b/app/javascript/controllers/divider_controller.js index 0047d252c..2cec61d8c 100644 --- a/app/javascript/controllers/divider_controller.js +++ b/app/javascript/controllers/divider_controller.js @@ -35,12 +35,9 @@ export default class extends Controller { moveDivider(event) { if (event.target.nodeName == DIVIDER_ITEM_NODE_NAME) { const rect = this.dividerTarget.getBoundingClientRect() - const distanceToTop = Math.abs(event.clientY - rect.top) - const distanceToBottom = Math.abs(event.clientY - (rect.top + rect.height)) - const distanceToNearestEdge = Math.min(distanceToTop, distanceToBottom) - const distancePercentage = (distanceToNearestEdge / rect.height) * 100 + const overlap = Math.abs((event.clientY - rect.top) / rect.height) - if (distancePercentage > 50) { + if (overlap > 0.5) { this.#moveDividerTo(this.#items.indexOf(event.target)) } } From 8877d2e66df96b61b741cd0dd6de1762521d9990 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Thu, 16 Jan 2025 15:09:46 -0600 Subject: [PATCH 3/4] Use distance to nearest edge This feels the smoothest --- app/javascript/controllers/divider_controller.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/javascript/controllers/divider_controller.js b/app/javascript/controllers/divider_controller.js index 2cec61d8c..553065c30 100644 --- a/app/javascript/controllers/divider_controller.js +++ b/app/javascript/controllers/divider_controller.js @@ -2,6 +2,7 @@ import { Controller } from "@hotwired/stimulus" const MOVE_ITEM_DATA_TYPE = "x-fizzy/move" const DIVIDER_ITEM_NODE_NAME = "LI" +const OVERLAP_THRESHOLD = 0.25 export default class extends Controller { static targets = [ "divider", "dragImage", "count" ] @@ -35,9 +36,12 @@ export default class extends Controller { moveDivider(event) { if (event.target.nodeName == DIVIDER_ITEM_NODE_NAME) { const rect = this.dividerTarget.getBoundingClientRect() - const overlap = Math.abs((event.clientY - rect.top) / rect.height) + const distanceToTop = Math.abs(event.clientY - rect.top) + const distanceToBottom = Math.abs(event.clientY - (rect.top + rect.height)) + const distanceToNearestEdge = Math.min(distanceToTop, distanceToBottom) + const overlap = (distanceToNearestEdge / rect.height) - if (overlap > 0.5) { + if (overlap > OVERLAP_THRESHOLD) { this.#moveDividerTo(this.#items.indexOf(event.target)) } } From fb27cee9b0d410d3e654617d197acbca120dde18 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Thu, 16 Jan 2025 15:11:44 -0600 Subject: [PATCH 4/4] Unnecessary parens --- app/javascript/controllers/divider_controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/controllers/divider_controller.js b/app/javascript/controllers/divider_controller.js index 553065c30..058bcb6a0 100644 --- a/app/javascript/controllers/divider_controller.js +++ b/app/javascript/controllers/divider_controller.js @@ -39,7 +39,7 @@ export default class extends Controller { const distanceToTop = Math.abs(event.clientY - rect.top) const distanceToBottom = Math.abs(event.clientY - (rect.top + rect.height)) const distanceToNearestEdge = Math.min(distanceToTop, distanceToBottom) - const overlap = (distanceToNearestEdge / rect.height) + const overlap = distanceToNearestEdge / rect.height if (overlap > OVERLAP_THRESHOLD) { this.#moveDividerTo(this.#items.indexOf(event.target))