mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-11-13 12:13:42 +01:00
Show a dragged column's drop line at every boundary
The line was hidden while a drop would leave the column where it is, so a drag showed nothing until it crossed a neighbour's middle. It now shows from the first movement, on the nearer edge of the column's own slot when the drop would change nothing, and at the first boundary over the mark column. The choice of boundary moves to a tested function in the columns module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
78351f620e
commit
9ee37e4015
3 files changed
+49
-9
No files matched your search
@@ -38,6 +38,7 @@ import {
|
||||
type ColumnPrefs,
|
||||
type CustomColumnId,
|
||||
canHide,
|
||||
dropBoundary,
|
||||
hideOtherColumns,
|
||||
isCustomColumn,
|
||||
moveColumn,
|
||||
@@ -409,7 +410,7 @@ function useColumnDrag({
|
||||
id: ColumnId;
|
||||
/** The pointer, across the window */
|
||||
x: number;
|
||||
/** The boundary it would drop at, and that boundary's line, or null where it would not move */
|
||||
/** The boundary it would move to, null where it would stay, and the line drawn on it */
|
||||
to: number | null;
|
||||
line: number | null;
|
||||
frame: number;
|
||||
@@ -433,6 +434,8 @@ function useColumnDrag({
|
||||
if (column == null) return;
|
||||
state.current = { id: column.id, x: pointer.current, to: null, line: null, frame: 0 };
|
||||
setDragging(column);
|
||||
// The line shows from the drag's first movement, not a frame later
|
||||
target(state.current);
|
||||
|
||||
const tick = () => {
|
||||
const s = state.current;
|
||||
@@ -511,18 +514,14 @@ function useColumnDrag({
|
||||
|
||||
/** Sets where the drag would drop, from the pointer and the labels where they are now */
|
||||
function target(s: NonNullable<typeof state.current>) {
|
||||
// The boundary before the first label whose middle is right of the pointer
|
||||
const cells = Array.from(
|
||||
gridRef.current?.querySelectorAll<HTMLElement>(":scope > [data-column]") ?? [],
|
||||
).map((el) => el.getBoundingClientRect());
|
||||
let to = cells.findIndex((r) => s.x < r.left + r.width / 2);
|
||||
if (to === -1) to = cells.length;
|
||||
// Where it already is, it would not move, so no line. Its place is read each time, as the
|
||||
// columns can change under a drag: Operation shows itself when a flow has one.
|
||||
// Its place is read each time, as the columns can change under a drag: Operation shows
|
||||
// itself when a flow has one.
|
||||
const from = latest.current.columns.findIndex((c) => c.id === s.id);
|
||||
const moves = from !== -1 && to !== from && to !== from + 1;
|
||||
s.to = moves ? to : null;
|
||||
const line = moves ? (cells[to]?.left ?? cells.at(-1)?.right ?? null) : null;
|
||||
const { to, line } = dropBoundary(s.x, cells, from);
|
||||
s.to = to;
|
||||
// Told again only when it changes: another boundary, or the same one scrolled
|
||||
if (line !== s.line) latest.current.onDropLine(line);
|
||||
s.line = line;
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
customPathProblem,
|
||||
customValue,
|
||||
defaultColumnPrefs,
|
||||
dropBoundary,
|
||||
fieldReference,
|
||||
fieldReferenceChanges,
|
||||
gridTemplate,
|
||||
@@ -322,6 +323,27 @@ describe("column order", () => {
|
||||
expect(parseColumnPrefs({ order: "time" }).order).toEqual([]);
|
||||
});
|
||||
|
||||
test("the drop line shows at every boundary, its own slot's edges included", () => {
|
||||
// Four columns 100px wide from x 24, after the mark column; the third is dragged
|
||||
const cells = [24, 124, 224, 324].map((left) => ({ left, right: left + 100 }));
|
||||
const at = (x: number) => dropBoundary(x, cells, 2);
|
||||
// Over the mark column or the first's left half: the first boundary
|
||||
expect(at(5)).toEqual({ to: 0, line: 24 });
|
||||
expect(at(60)).toEqual({ to: 0, line: 24 });
|
||||
expect(at(80)).toEqual({ to: 1, line: 124 });
|
||||
// The left neighbour's near half and its own left half: its left edge, staying
|
||||
expect(at(190)).toEqual({ to: null, line: 224 });
|
||||
expect(at(250)).toEqual({ to: null, line: 224 });
|
||||
// Its own right half and the right neighbour's near half: its right edge, staying
|
||||
expect(at(290)).toEqual({ to: null, line: 324 });
|
||||
expect(at(350)).toEqual({ to: null, line: 324 });
|
||||
// Past the right neighbour's middle, and past the end
|
||||
expect(at(380)).toEqual({ to: 4, line: 424 });
|
||||
expect(at(900)).toEqual({ to: 4, line: 424 });
|
||||
// The last column dragged to the end stays
|
||||
expect(dropBoundary(900, cells, 3)).toEqual({ to: null, line: 424 });
|
||||
});
|
||||
|
||||
test("Reset Column Order puts every column back", () => {
|
||||
let prefs = moveColumn(defaultColumnPrefs, "time", 0);
|
||||
prefs = toggleColumn(prefs, "latency");
|
||||
|
||||
@@ -298,6 +298,25 @@ export function resetOrder(prefs: ColumnPrefs): ColumnPrefs {
|
||||
return { ...prefs, order: [] };
|
||||
}
|
||||
|
||||
/**
|
||||
* Where a dragged column would drop, from the pointer and the shown columns' edges, left to
|
||||
* right: the boundary before the first column whose middle is right of the pointer, and the
|
||||
* line's place on it. Over its own column or the near half of a neighbour, that is an edge of
|
||||
* its own slot, where it would stay, so `to` is null; the line still shows there. Left of the
|
||||
* first column, over the fixed mark column, it is the first boundary.
|
||||
*/
|
||||
export function dropBoundary(
|
||||
x: number,
|
||||
cells: { left: number; right: number }[],
|
||||
from: number,
|
||||
): { to: number | null; line: number | null } {
|
||||
let at = cells.findIndex((r) => x < (r.left + r.right) / 2);
|
||||
if (at === -1) at = cells.length;
|
||||
const line = cells[at]?.left ?? cells.at(-1)?.right ?? null;
|
||||
const stays = from === -1 || at === from || at === from + 1;
|
||||
return { to: stays ? null : at, line };
|
||||
}
|
||||
|
||||
/** Shows `id` alone */
|
||||
export function hideOtherColumns(prefs: ColumnPrefs, id: ColumnId): ColumnPrefs {
|
||||
const visible: ColumnPrefs["visible"] = {};
|
||||
|
||||
Reference in new issue
Block a user