Let a filter rule be dragged into place
Twenty-five rules and two buttons that move one place at a time meant a rule pushed to the wrong end cost ten clicks to bring back. It can now be dragged. A grip on the left of each card arms the drag, so the switch, the name and the buttons still take a plain click, and the up and down buttons stay for the keyboard. The card being dragged fades; the one under the pointer draws a line on the edge the rule would land on, top half or bottom. The guard against dropping a rule onto itself reads a ref rather than state: dragstart and the first dragover can arrive in the same frame, and a stale read there drew a drop line on the card being dragged. Found by driving the real thing in a browser, and covered by a test that fires the two events back to back.
This commit is contained in:
@@ -210,6 +210,20 @@ export function upsertRule(rules: SieveRule[], rule: SieveRule): SieveRule[] {
|
||||
return rules.some((x) => x.id === rule.id) ? rules.map((x) => (x.id === rule.id ? rule : x)) : [...rules, rule];
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the rule `fromId` to sit either side of `toId`. `below` says which,
|
||||
* decided by which half of the target card the pointer was over.
|
||||
*/
|
||||
export function reorderRules(rules: SieveRule[], fromId: string, toId: string, below: boolean): SieveRule[] {
|
||||
if (fromId === toId) return rules;
|
||||
const moved = rules.find((r) => r.id === fromId);
|
||||
const rest = rules.filter((r) => r.id !== fromId);
|
||||
const target = rest.findIndex((r) => r.id === toId);
|
||||
if (!moved || target < 0) return rules;
|
||||
const at = below ? target + 1 : target;
|
||||
return [...rest.slice(0, at), moved, ...rest.slice(at)];
|
||||
}
|
||||
|
||||
export function describeRule(r: SieveRule): string {
|
||||
const tests = r.tests
|
||||
.map((t) => {
|
||||
|
||||
Reference in New Issue
Block a user