Move Menu into a separate component

This commit is contained in:
Jos de Jong 2020-07-26 12:00:14 +02:00
parent e23e4a82dd
commit e629b404a6
4 changed files with 192 additions and 147 deletions

View File

@ -9,58 +9,6 @@
flex-direction: column;
position: relative;
.menu {
font-family: $font-family-menu;
font-size: $font-size;
background: $theme-color;
color: $white;
display: flex;
align-items: center;
position: relative;
.button {
width: $menu-button-size;
height: $menu-button-size;
border: none;
background: transparent;
color: white;
cursor: pointer;
padding: 0;
&:hover,
&:focus {
background: rgba(255, 255, 255, 0.3);
}
&:disabled {
color: rgba(255, 255, 255, 0.5);
background: transparent;
}
}
.space {
flex: 1;
}
.separator {
$margin: 3px;
background: rgba(255, 255, 255, 0.15);
box-sizing: border-box;
width: 1px;
height: $menu-button-size - 2 * $margin;
margin: $margin;
}
.search-box-container {
position: absolute;
top: 100%;
right: $search-box-offset + 20px; // keep space for scrollbar
margin-top: $search-box-offset;
z-index: 2;
}
}
.hidden-input-label {
position: absolute;
right: 0;

View File

@ -13,9 +13,6 @@
SCROLL_DURATION,
STATE_PROPS
} from './constants.js'
import SearchBox from './SearchBox.svelte'
import Icon from 'svelte-awesome'
import { faCut, faClone, faCopy, faPaste, faSearch, faUndo, faRedo } from '@fortawesome/free-solid-svg-icons'
import { createHistory } from './history.js'
import JSONNode from './JSONNode.svelte'
import {
@ -37,6 +34,7 @@
import jump from './assets/jump.js/src/jump.js'
import { expandPath, stateUtils } from './utils/stateUtils.js'
import { getNextKeys, patchProps } from './utils/updateProps.js'
import Menu from './Menu.svelte'
let divContents
let domHiddenInput
@ -247,27 +245,22 @@
}
}
async function changeSearchText (text) {
async function handleSearchText (text) {
searchText = text
await tick() // await for the search results to be updated
focusActiveSearchResult(searchResult && searchResult.activeItem)
}
async function nextSearchResult () {
async function handleNextSearchResult () {
searchResult = searchNext(searchResult)
focusActiveSearchResult(searchResult && searchResult.activeItem)
}
function previousSearchResult () {
function handlePreviousSearchResult () {
searchResult = searchPrevious(searchResult)
focusActiveSearchResult(searchResult && searchResult.activeItem)
}
function clearSearchResult () {
showSearch = false
searchText = ''
}
async function focusActiveSearchResult (activeItem) {
if (activeItem) {
state = expandPath(state, activeItem.path)
@ -316,10 +309,6 @@
// should never be called on the root
}
function handleToggleSearch() {
showSearch = !showSearch
}
/**
* Toggle expanded state of a node
* @param {Path} path
@ -440,88 +429,25 @@
</script>
<div class="jsoneditor" on:keydown={handleKeyDown}>
<div class="menu">
<button
class="button cut"
on:click={handleCut}
disabled={!hasSelectionContents}
title="Cut (Ctrl+X)"
>
<Icon data={faCut} />
</button>
<button
class="button copy"
on:click={handleCopy}
disabled={!hasSelectionContents}
title="Copy (Ctrl+C)"
>
<Icon data={faCopy} />
</button>
<button
class="button paste"
on:click={handlePaste}
disabled={!hasClipboardContents}
title="Paste (Ctrl+V)"
>
<Icon data={faPaste} />
</button>
<Menu
historyState={historyState}
searchText={searchText}
searchResult={searchResult}
bind:showSearch
hasSelectionContents={hasSelectionContents}
hasClipboardContents={hasClipboardContents}
<div class="separator"></div>
onCut={handleCut}
onCopy={handleCopy}
onPaste={handlePaste}
onDuplicate={handleDuplicate}
onUndo={handleUndo}
onRedo={handleRedo}
<button
class="button duplicate"
on:click={handleDuplicate}
disabled={!hasSelectionContents}
title="Duplicate (Ctrl+D)"
>
<Icon data={faClone} />
</button>
<div class="separator"></div>
<button
class="button search"
on:click={handleToggleSearch}
title="Search (Ctrl+F)"
>
<Icon data={faSearch} />
</button>
<div class="separator"></div>
<button
class="button undo"
disabled={!historyState.canUndo}
on:click={handleUndo}
title="Undo (Ctrl+Z)"
>
<Icon data={faUndo} />
</button>
<button
class="button redo"
disabled={!historyState.canRedo}
on:click={handleRedo}
title="Redo (Ctrl+Shift+Z)"
>
<Icon data={faRedo} />
</button>
<div class="space"></div>
{#if showSearch}
<div class="search-box-container">
<SearchBox
text={searchText}
resultCount={searchResult ? searchResult.count : 0}
activeIndex={searchResult ? searchResult.activeIndex : 0}
onChange={changeSearchText}
onNext={nextSearchResult}
onPrevious={previousSearchResult}
onClose={clearSearchResult}
/>
</div>
{/if}
</div>
onSearchText={handleSearchText}
onNextSearchResult={handleNextSearchResult}
onPreviousSearchResult={handlePreviousSearchResult}
/>
<label class="hidden-input-label">
<input
class="hidden-input"

53
src/Menu.scss Normal file
View File

@ -0,0 +1,53 @@
@import './styles.scss';
.menu {
font-family: $font-family-menu;
font-size: $font-size;
background: $theme-color;
color: $white;
display: flex;
align-items: center;
position: relative;
.button {
width: $menu-button-size;
height: $menu-button-size;
border: none;
background: transparent;
color: white;
cursor: pointer;
padding: 0;
&:hover,
&:focus {
background: rgba(255, 255, 255, 0.3);
}
&:disabled {
color: rgba(255, 255, 255, 0.5);
background: transparent;
}
}
.space {
flex: 1;
}
.separator {
$margin: 3px;
background: rgba(255, 255, 255, 0.15);
box-sizing: border-box;
width: 1px;
height: $menu-button-size - 2 * $margin;
margin: $margin;
}
.search-box-container {
position: absolute;
top: 100%;
right: $search-box-offset + 20px; // keep space for scrollbar
margin-top: $search-box-offset;
z-index: 2;
}
}

118
src/Menu.svelte Normal file
View File

@ -0,0 +1,118 @@
<script>
import Icon from 'svelte-awesome'
import { faCut, faClone, faCopy, faPaste, faSearch, faUndo, faRedo } from '@fortawesome/free-solid-svg-icons'
import SearchBox from './SearchBox.svelte'
export let searchText
export let searchResult
export let showSearch = false
export let hasSelectionContents
export let hasClipboardContents
export let historyState
export let onCut
export let onCopy
export let onPaste
export let onDuplicate
export let onUndo
export let onRedo
export let onSearchText
export let onNextSearchResult
export let onPreviousSearchResult
function handleToggleSearch() {
showSearch = !showSearch
}
function clearSearchResult () {
showSearch = false
onSearchText('')
}
</script>
<div class="menu">
<button
class="button cut"
on:click={onCut}
disabled={!hasSelectionContents}
title="Cut (Ctrl+X)"
>
<Icon data={faCut} />
</button>
<button
class="button copy"
on:click={onCopy}
disabled={!hasSelectionContents}
title="Copy (Ctrl+C)"
>
<Icon data={faCopy} />
</button>
<button
class="button paste"
on:click={onPaste}
disabled={!hasClipboardContents}
title="Paste (Ctrl+V)"
>
<Icon data={faPaste} />
</button>
<div class="separator"></div>
<button
class="button duplicate"
on:click={onDuplicate}
disabled={!hasSelectionContents}
title="Duplicate (Ctrl+D)"
>
<Icon data={faClone} />
</button>
<div class="separator"></div>
<button
class="button search"
on:click={handleToggleSearch}
title="Search (Ctrl+F)"
>
<Icon data={faSearch} />
</button>
<div class="separator"></div>
<button
class="button undo"
disabled={!historyState.canUndo}
on:click={onUndo}
title="Undo (Ctrl+Z)"
>
<Icon data={faUndo} />
</button>
<button
class="button redo"
disabled={!historyState.canRedo}
on:click={onRedo}
title="Redo (Ctrl+Shift+Z)"
>
<Icon data={faRedo} />
</button>
<div class="space"></div>
{#if showSearch}
<div class="search-box-container">
<SearchBox
text={searchText}
resultCount={searchResult ? searchResult.count : 0}
activeIndex={searchResult ? searchResult.activeIndex : 0}
onChange={onSearchText}
onNext={onNextSearchResult}
onPrevious={onPreviousSearchResult}
onClose={clearSearchResult}
/>
</div>
{/if}
</div>
<style src="Menu.scss"></style>