InplaceEdit and TreeView component.
This commit is contained in:
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
0
src/app.css
Normal file
0
src/app.css
Normal file
58
src/lib/InPlaceEdit.svelte
Normal file
58
src/lib/InPlaceEdit.svelte
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<script>
|
||||||
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
|
|
||||||
|
export let value, required = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
let editing = false, original
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
original = value
|
||||||
|
})
|
||||||
|
|
||||||
|
function edit() {
|
||||||
|
editing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
if (value != original) {
|
||||||
|
dispatch('submit', value)
|
||||||
|
}
|
||||||
|
|
||||||
|
editing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function keydown(event) {
|
||||||
|
if (event.key == 'Escape') {
|
||||||
|
event.preventDefault()
|
||||||
|
value = original
|
||||||
|
editing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function focus(element) {
|
||||||
|
element.focus()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if editing}
|
||||||
|
<form on:submit|preventDefault={submit} on:keydown={keydown}>
|
||||||
|
<input bind:value on:blur={submit} {required} use:focus/>
|
||||||
|
</form>
|
||||||
|
{:else}
|
||||||
|
<div on:click={edit}>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
input {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
font-size: inherit;
|
||||||
|
color: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
text-align: inherit;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
54
src/lib/TreeView.svelte
Normal file
54
src/lib/TreeView.svelte
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<script context="module">
|
||||||
|
// retain module scoped expansion state for each tree node
|
||||||
|
const _expansionState = {
|
||||||
|
/* treeNodeId: expanded <boolean> */
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
// import { slide } from 'svelte/transition'
|
||||||
|
export let tree
|
||||||
|
const {label, children} = tree
|
||||||
|
|
||||||
|
let expanded = _expansionState[label] || false
|
||||||
|
const toggleExpansion = () => {
|
||||||
|
expanded = _expansionState[label] = !expanded
|
||||||
|
}
|
||||||
|
$: arrowDown = expanded
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul><!-- transition:slide -->
|
||||||
|
<li>
|
||||||
|
{#if children}
|
||||||
|
<span on:click={toggleExpansion}>
|
||||||
|
<span class="arrow" class:arrowDown>▶</span>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
{#if expanded}
|
||||||
|
{#each children as child}
|
||||||
|
<svelte:self tree={child} />
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
{:else}
|
||||||
|
<span>
|
||||||
|
<span class="no-arrow"/>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 1.2rem;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.no-arrow { padding-left: 1.0rem; }
|
||||||
|
.arrow {
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
/* transition: transform 200ms; */
|
||||||
|
}
|
||||||
|
.arrowDown { transform: rotate(90deg); }
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user