Create dropdown menu (WIP)
This commit is contained in:
parent
c441663528
commit
a6bb790f5e
|
@ -0,0 +1,46 @@
|
|||
@import '../styles.scss';
|
||||
|
||||
.menu-dropdown {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type : none;
|
||||
}
|
||||
}
|
||||
|
||||
.items {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
background: white;
|
||||
z-index: 2;
|
||||
color: $black;
|
||||
box-shadow: $box-shadow;
|
||||
|
||||
&.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
|
||||
&:hover {
|
||||
background: $background-gray;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
color: $gray;
|
||||
background: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<script>
|
||||
import Icon from 'svelte-awesome'
|
||||
import { faCaretDown } from '@fortawesome/free-solid-svg-icons'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
import { keyComboFromEvent} from '../utils/keyBindings.js'
|
||||
|
||||
/** @type {MenuDropdownItem[]} */
|
||||
export let items = []
|
||||
|
||||
export let title = null
|
||||
export let width = '120px'
|
||||
export let visible = false
|
||||
export let disabled = false
|
||||
|
||||
function toggleShow (event) {
|
||||
event.stopPropagation()
|
||||
visible = !visible
|
||||
}
|
||||
|
||||
function handleClick () {
|
||||
visible = false
|
||||
}
|
||||
|
||||
function handleKeyDown (event) {
|
||||
const combo = keyComboFromEvent(event)
|
||||
if (combo === 'Escape') {
|
||||
event.preventDefault()
|
||||
visible = false
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
document.addEventListener('click', handleClick)
|
||||
document.addEventListener('keydown', handleKeyDown)
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
document.removeEventListener('click', handleClick)
|
||||
document.removeEventListener('keydown', handleKeyDown)
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="menu-dropdown" title={title} on:click={handleClick}>
|
||||
<slot name="defaultItem"></slot>
|
||||
|
||||
<button on:click={toggleShow}>
|
||||
<Icon data={faCaretDown} />
|
||||
</button>
|
||||
|
||||
<div class="items" class:visible style="width: {width};">
|
||||
<ul>
|
||||
{#each items as item}
|
||||
<li>
|
||||
<button on:click={item.onClick} disabled={disabled}>
|
||||
{item.text}
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style src="./DropdownMenu.scss"></style>
|
|
@ -45,8 +45,6 @@
|
|||
|
||||
let selection = null
|
||||
let clipboard = null
|
||||
$: hasSelectionContents = selection != null && selection.paths != null
|
||||
$: hasClipboardContents = clipboard != null && selection != null
|
||||
|
||||
$: state = syncState(doc, state, [], (path) => path.length < 1)
|
||||
|
||||
|
@ -209,6 +207,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
function handleInsert() {
|
||||
|
||||
if (selection != null) {
|
||||
console.log('insert', { selection })
|
||||
|
||||
// TODO: impelemnt insert
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: cleanup
|
||||
$: console.log('doc', doc)
|
||||
$: console.log('state', state)
|
||||
|
@ -382,6 +389,10 @@
|
|||
event.preventDefault()
|
||||
handleDuplicate()
|
||||
}
|
||||
if (combo === 'Ctrl+Insert' || combo === 'Command+Insert') {
|
||||
event.preventDefault()
|
||||
handleInsert()
|
||||
}
|
||||
if (combo === 'Escape') {
|
||||
event.preventDefault()
|
||||
selection = null
|
||||
|
@ -433,8 +444,8 @@
|
|||
searchText={searchText}
|
||||
searchResult={searchResult}
|
||||
bind:showSearch
|
||||
hasSelectionContents={hasSelectionContents}
|
||||
hasClipboardContents={hasClipboardContents}
|
||||
selection={selection}
|
||||
clipboard={clipboard}
|
||||
|
||||
onCut={handleCut}
|
||||
onCopy={handleCopy}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { debounce, isEqual } from 'lodash-es'
|
||||
import { rename } from '../logic/operations.js'
|
||||
import { singleton } from './singleton.js'
|
||||
import {
|
||||
DEBOUNCE_DELAY,
|
||||
DEFAULT_LIMIT,
|
||||
|
@ -39,12 +40,6 @@
|
|||
export let onSelect
|
||||
export let selection
|
||||
|
||||
const singleton = {
|
||||
mousedown: false,
|
||||
selectionAnchor: null, // Path
|
||||
selectionFocus: null // Path
|
||||
}
|
||||
|
||||
$: expanded = state && state[STATE_EXPANDED]
|
||||
$: limit = state && state[STATE_LIMIT]
|
||||
$: props = state && state[STATE_PROPS]
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<script>
|
||||
import Icon from 'svelte-awesome'
|
||||
import { faCut, faClone, faCopy, faPaste, faSearch, faUndo, faRedo } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faCut, faClone, faCopy, faPaste, faSearch, faUndo, faRedo, faPlus } from '@fortawesome/free-solid-svg-icons'
|
||||
import SearchBox from './SearchBox.svelte'
|
||||
import DropdownMenu from './DropdownMenu.svelte'
|
||||
|
||||
export let searchText
|
||||
export let searchResult
|
||||
export let showSearch = false
|
||||
export let hasSelectionContents
|
||||
export let hasClipboardContents
|
||||
export let selection
|
||||
export let clipboard
|
||||
export let historyState
|
||||
|
||||
export let onCut
|
||||
|
@ -21,6 +22,10 @@
|
|||
export let onNextSearchResult
|
||||
export let onPreviousSearchResult
|
||||
|
||||
$: hasSelection = selection != null
|
||||
$: hasSelectionContents = selection != null && selection.paths != null
|
||||
$: hasClipboardContents = clipboard != null && selection != null
|
||||
|
||||
function handleToggleSearch() {
|
||||
showSearch = !showSearch
|
||||
}
|
||||
|
@ -30,6 +35,36 @@
|
|||
onSearchText('')
|
||||
}
|
||||
|
||||
function handleInsertValue () {
|
||||
console.log('TODO: insert value')
|
||||
}
|
||||
|
||||
/** @type {MenuDropdownItem[]} */
|
||||
const insertItems = [
|
||||
{
|
||||
text: "Insert value",
|
||||
onClick: handleInsertValue,
|
||||
default: true
|
||||
},
|
||||
{
|
||||
text: "Insert object",
|
||||
onClick: () => {
|
||||
console.log('TODO: insert object')
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Insert array",
|
||||
onClick: () => {
|
||||
console.log('TODO: insert array')
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Insert structure",
|
||||
onClick: () => {
|
||||
console.log('TODO: insert structure')
|
||||
}
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<div class="menu">
|
||||
|
@ -69,6 +104,21 @@
|
|||
<Icon data={faClone} />
|
||||
</button>
|
||||
|
||||
<DropdownMenu
|
||||
items={insertItems}
|
||||
title="Insert new value (Ctrl+Insert)"
|
||||
disabled={!hasSelection}
|
||||
>
|
||||
<button
|
||||
class="button insert"
|
||||
slot="defaultItem"
|
||||
on:click={handleInsertValue}
|
||||
disabled={!hasSelection}
|
||||
>
|
||||
<Icon data={faPlus} />
|
||||
</button>
|
||||
</DropdownMenu>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<button
|
||||
|
|
|
@ -6,7 +6,7 @@ $search-size: 24px;
|
|||
border: 2px solid $theme-color;
|
||||
border-radius: $border-radius;
|
||||
background: $white;
|
||||
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.24);
|
||||
box-shadow: $box-shadow;
|
||||
|
||||
.search-form {
|
||||
display: flex;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// used by JSONNode during dragging
|
||||
export const singleton = {
|
||||
mousedown: false,
|
||||
selectionAnchor: null, // Path
|
||||
selectionFocus: null // Path
|
||||
}
|
|
@ -26,6 +26,7 @@ $gray: #9d9d9d;
|
|||
$gray-icon: $gray;
|
||||
$light-gray: #c0c0c0;
|
||||
$selection-background: #e0e0e0;
|
||||
$background-gray: #f5f5f5;
|
||||
|
||||
$line-height: 18px;
|
||||
$indentation-width: 18px; // IMPORTANT: keep in sync with js constant INDENTATION_WIDTH
|
||||
|
@ -36,3 +37,15 @@ $border-radius: 3px;
|
|||
|
||||
$menu-padding: 5px;
|
||||
$bottom-height: 5px;
|
||||
|
||||
$box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.24);
|
||||
|
||||
button {
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
font-family: $font-family-menu;
|
||||
font-size: $font-size;
|
||||
padding: $menu-padding;
|
||||
}
|
||||
|
|
|
@ -75,3 +75,10 @@
|
|||
/**
|
||||
* @typedef {MultiSelectionSchema | BeforeSelection | AppendSelection} SelectionSchema
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} MenuDropdownItem
|
||||
* @property {string} text
|
||||
* @property {function} onClick
|
||||
* @property {boolean} [default=false]
|
||||
**/
|
||||
|
|
Loading…
Reference in New Issue