Skip to content

Commit

Permalink
fix: improve the behavior of the arrow quickkeys to navigate the cont…
Browse files Browse the repository at this point in the history
…ext menu (#83)
  • Loading branch information
josdejong authored May 23, 2022
1 parent 533a46c commit 76b177f
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 109 deletions.
8 changes: 7 additions & 1 deletion src/lib/components/controls/DropdownButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@
<div class="jse-dropdown-button" {title} on:click={handleClick}>
<slot name="defaultItem" />

<button type="button" class="jse-open-dropdown" class:jse-visible={visible} on:click={toggleShow}>
<button
type="button"
class="jse-open-dropdown"
data-type="jse-open-dropdown"
class:jse-visible={visible}
on:click={toggleShow}
>
<Icon data={faCaretDown} />
</button>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import { createDebug } from '../../../utils/debug'
import Message from '../../controls/Message.svelte'
import { onDestroy, onMount } from 'svelte'
import { activeElementIsChildOf, getWindow } from '../../../utils/domUtils.js'
import { activeElementIsChildOf, getWindow } from '../../../utils/domUtils'
import { normalizeJsonParseError } from '../../../utils/jsonUtils.ts'
import { createFocusTracker } from '../../controls/createFocusTracker.js'
import Menu from '../../controls/Menu.svelte'
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/modes/treemode/JSONKey.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { SELECTION_TYPE } from '$lib/logic/selection'
import SearchResultHighlighter from './highlight/SearchResultHighlighter.svelte'
import EditableDiv from '../../controls/EditableDiv.svelte'
import { addNewLineSuffix } from '$lib/utils/domUtils'
import { addNewLineSuffix } from '../../../utils/domUtils'
import { UPDATE_SELECTION } from '../../../constants.js'
export let path
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/modes/treemode/JSONNode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import { forEachKey } from '../../../logic/documentState.js'
import { onMoveSelection } from '../../../logic/dragging.js'
import { forEachIndex } from '../../../utils/arrayUtils.ts'
import { getDataPathFromTarget } from '../../../utils/domUtils.js'
import { getDataPathFromTarget } from '../../../utils/domUtils'
import { createMemoizePath } from '../../../utils/pathUtils.js'
import { keyIsSelected } from '../../../logic/selection.js'
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/modes/treemode/JSONValue.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<script lang="ts">
import { SELECTION_TYPE } from '$lib/logic/selection'
import { isEqual } from 'lodash-es'
import type { SearchResultItem, Selection, TreeModeContext, Path } from '../../../types'
import type { SearchResultItem, Selection, Path } from '../../../types'
export let path: Path
export let value: JSON
Expand Down
118 changes: 16 additions & 102 deletions src/lib/components/modes/treemode/contextmenu/ContextMenu.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<svelte:options immutable={true} />

<script>
<script lang="ts">
import {
faCaretSquareDown,
faCaretSquareUp,
Expand All @@ -26,6 +26,7 @@
import { STATE_ENFORCE_STRING } from '$lib/constants'
import { isObject } from '../../../../utils/typeUtils.ts'
import { canConvert, singleItemSelected } from '../../../../logic/selection.js'
import { findNearestElement } from '../../../../utils/domUtils'
export let json
export let state
Expand Down Expand Up @@ -200,50 +201,24 @@
function handleKeyDown(event) {
const combo = keyComboFromEvent(event).replace(/^Command\+/, 'Ctrl+')
/**
* Find first enabled sibling button.
* Uses hints from the button attributes itself: data-name, data-up,
* data-down, data-left, data-right.
* @param {Element} currentButton
* @param {'left' | 'right' | 'up' | 'down'} direction
*/
function findNextButton(currentButton, direction) {
const optionsString = currentButton.getAttribute('data-' + direction)
if (optionsString) {
const options = optionsString.split(',')
// Step 1: find exact match
for (const option of options) {
const match = refContextMenu.querySelector(`button[data-name="${option}"]`)
if (match && !match.disabled) {
return match
}
}
if (combo === 'Up' || combo === 'Down' || combo === 'Left' || combo === 'Right') {
event.preventDefault()
// Step 2: recurse over multiple buttons to find an enabled one
for (const option of options) {
const match = refContextMenu.querySelector(`button[data-name="${option}"]`)
if (match && match.disabled) {
const match2 = findNextButton(match, direction)
if (match2) {
return match2
}
}
const buttons: HTMLButtonElement[] = Array.from(
refContextMenu.querySelectorAll('button:not([disabled])')
)
const nearest = findNearestElement({
allElements: buttons,
currentElement: event.target,
direction: combo,
hasPrio: (element: HTMLButtonElement) => {
return element.getAttribute('data-type') !== 'jse-open-dropdown'
}
})
if (nearest) {
nearest.focus()
}
}
function focusNextButton(currentButton, direction) {
const next = findNextButton(currentButton, direction)
if (next) {
next.focus()
}
}
if (combo === 'Up' || combo === 'Down' || combo === 'Left' || combo === 'Right') {
event.preventDefault()
focusNextButton(event.target, combo.toLowerCase())
}
}
$: editValueDropdownItems = [
Expand Down Expand Up @@ -303,9 +278,6 @@
<button
type="button"
title="Edit the key (Double-click on the key)"
data-name="edit-key"
data-down="cut,copy,paste"
data-right="edit-value"
on:click={handleEditKey}
disabled={!canEditKey}
>
Expand All @@ -316,9 +288,6 @@
type="button"
slot="defaultItem"
title="Edit the value (Double-click on the value)"
data-name="edit-value"
data-down="paste,copy,cut"
data-left="edit-key"
on:click={handleEditValue}
disabled={!canEditValue}
>
Expand All @@ -333,10 +302,6 @@
type="button"
slot="defaultItem"
title="Cut selected contents, formatted with indentation (Ctrl+X)"
data-name="cut"
data-up="edit-key,edit-value"
data-down="remove"
data-right="copy"
on:click={handleCut}
disabled={!hasSelectionContents}
>
Expand All @@ -348,11 +313,6 @@
type="button"
slot="defaultItem"
title="Copy selected contents, formatted with indentation (Ctrl+C)"
data-name="copy"
data-up="edit-key,edit-value"
data-down="insert-structure"
data-left="cut"
data-right="paste"
on:click={handleCopy}
disabled={!hasSelectionContents}
>
Expand All @@ -362,10 +322,6 @@
<button
type="button"
title="Paste clipboard contents (Ctrl+V)"
data-name="paste"
data-up="edit-value,edit-key"
data-down="insert-structure"
data-left="copy"
on:click={handlePaste}
disabled={!hasSelection}
>
Expand All @@ -378,10 +334,6 @@
<button
type="button"
title="Remove selected contents (Delete)"
data-name="remove"
data-up="cut,copy,paste"
data-down="duplicate"
data-right="insert-structure"
on:click={handleRemove}
disabled={!hasSelectionContents}
>
Expand All @@ -390,10 +342,6 @@
<button
type="button"
title="Duplicate selected contents (Ctrl+D)"
data-name="duplicate"
data-up="remove"
data-down="extract"
data-right="insert-structure"
on:click={handleDuplicate}
disabled={!canDuplicate}
>
Expand All @@ -402,10 +350,6 @@
<button
type="button"
title="Extract selected contents"
data-name="extract"
data-up="duplicate"
data-down="sort"
data-right="insert-object"
on:click={handleExtract}
disabled={!canExtract}
>
Expand All @@ -414,10 +358,6 @@
<button
type="button"
title="Sort array or object contents"
data-name="sort"
data-up="extract"
data-down="transform"
data-right="insert-array"
on:click={handleSort}
disabled={!hasSelectionContents}
>
Expand All @@ -426,10 +366,6 @@
<button
type="button"
title="Transform array or object contents (filter, sort, project)"
data-name="transform"
data-up="sort"
data-down="insert-before"
data-right="insert-value"
on:click={handleTransform}
disabled={!hasSelectionContents}
>
Expand All @@ -444,10 +380,6 @@
type="button"
on:click={() => handleInsertOrConvert('structure')}
title="{insertOrConvertText} structure"
data-name="insert-structure"
data-up="paste,copy,cut"
data-down="insert-object"
data-left="duplicate"
disabled={!canInsertOrConvertStructure}
>
<span class="jse-insert"><span class="jse-plus">{'+'}</span></span> Structure
Expand All @@ -456,10 +388,6 @@
type="button"
on:click={() => handleInsertOrConvert('object')}
title="{insertOrConvertText} object"
data-name="insert-object"
data-up="insert-structure"
data-down="insert-array"
data-left="extract"
disabled={!canInsertOrConvertObject}
>
<span class="jse-insert">{'{}'}</span> Object
Expand All @@ -468,10 +396,6 @@
type="button"
on:click={() => handleInsertOrConvert('array')}
title="{insertOrConvertText} array"
data-name="insert-array"
data-up="insert-object"
data-down="insert-value"
data-left="sort"
disabled={!canInsertOrConvertArray}
>
<span class="jse-insert">[]</span> Array
Expand All @@ -480,10 +404,6 @@
type="button"
on:click={() => handleInsertOrConvert('value')}
title="{insertOrConvertText} value"
data-name="insert-value"
data-up="insert-array"
data-down="insert-after"
data-left="transform"
disabled={!canInsertOrConvertValue}
>
<span class="jse-insert"><span class="jse-quote">"</span></span> Value
Expand All @@ -495,9 +415,6 @@
<button
type="button"
title="Select area before current entry to insert or paste contents"
data-name="insert-before"
data-up="transform"
data-right="insert-after"
disabled={!hasSelectionContents || rootSelected}
on:click={handleInsertBefore}
>
Expand All @@ -506,9 +423,6 @@
<button
type="button"
title="Select area after current entry to insert or paste contents"
data-name="insert-after"
data-up="insert-value"
data-left="insert-before"
disabled={!hasSelectionContents || rootSelected}
on:click={handleInsertAfter}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script>
import { splitValue } from '$lib/logic/search'
import { addNewLineSuffix } from '$lib/utils/domUtils.js'
import { addNewLineSuffix } from '$lib/utils/domUtils'
/** @type {string} */
export let text
Expand Down
2 changes: 1 addition & 1 deletion src/lib/plugins/value/components/ReadonlyValue.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { SELECTION_TYPE } from '$lib/logic/selection.js'
import SearchResultHighlighter from '../../../components/modes/treemode/highlight/SearchResultHighlighter.svelte'
import { getValueClass } from './utils/getValueClass'
import { addNewLineSuffix } from '$lib/utils/domUtils.js'
import { addNewLineSuffix } from '$lib/utils/domUtils'
export let path
export let value
Expand Down
Loading

0 comments on commit 76b177f

Please sign in to comment.