From 2ba1330b38ae19f1e17197a2819fc59d458e8a8e Mon Sep 17 00:00:00 2001 From: Yichuan Shen Date: Thu, 23 Jan 2020 15:44:29 +0100 Subject: [PATCH] Use tab to cycle through edges #39 --- src/components/App.js | 37 ++++++++++++++++++++++++++++++++++++- src/helper.js | 14 ++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/components/App.js b/src/components/App.js index 316bd1c..07473fb 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -1,7 +1,7 @@ import {h, render, Component} from 'preact' import copyText from 'copy-text-to-clipboard' import * as diagram from '../diagram' -import {arrAdd} from '../helper' +import {arrAdd, lexicalCompare} from '../helper' import Grid from './Grid' import Properties from './Properties' @@ -60,6 +60,41 @@ export default class App extends Component { ? null : {selectedCell: arrAdd(state.selectedCell, arrowControl[evt.key])} ) + } else if (evt.key === 'Tab' && this.state.selectedArrow != null) { + // Neutralize browser focus mechanism and instead cycle through arrows + + evt.preventDefault() + evt.stopPropagation() + + let diff = evt.shiftKey ? -1 : 1 + + this.setState(state => { + if (state.selectedArrow == null) return + + let {nodes, edges} = state.diagram + let length = edges.length + let findNodePositionById = id => + nodes.find(node => node.id === id).position + + // Constructing a natural tab order for edges + + let indices = [...Array(length)] + .map((_, i) => [ + i, + [edges[i].from, edges[i].to] + .map(findNodePositionById) + .reduce((sum, x) => arrAdd(sum, x), [0, 0]) + ]) + .sort(([_, arr1], [__, arr2]) => lexicalCompare(arr1, arr2)) + .map(([i, _]) => i) + + let metaIndex = indices.indexOf(state.selectedArrow) + + return { + selectedArrow: + indices[(((metaIndex + diff) % length) + length) % length] + } + }) } else if (evt.key === 'Enter') { this.setState(state => state.cellEditMode || state.selectedArrow != null diff --git a/src/helper.js b/src/helper.js index eca9c59..05168a5 100644 --- a/src/helper.js +++ b/src/helper.js @@ -8,6 +8,20 @@ export function clamp(min, max, x) { return Math.max(min, Math.min(max, x)) } +export function lexicalCompare(arr1, arr2) { + if (arr1.length != arr2.length) { + return arr1.length - arr2.length + } else if (arr1.length === 0) { + return 0 + } + + return arr1[0] < arr2[0] + ? -1 + : arr1[0] > arr2[0] + ? 1 + : lexicalCompare(arr1.slice(1), arr2.slice(1)) +} + export function arrEquals(a, b) { return a.length === b.length && a.every((x, i) => x === b[i]) }