Last active
January 11, 2024 14:04
-
-
Save b3b00/de955201c084dbe41b1baae861bfda00 to your computer and use it in GitHub Desktop.
svelte filterable TreeView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
import TreeView from './TreeView.svelte'; | |
import Node from './Node.svelte'; | |
import {selectedNode} from './teststore.js' | |
let name = 'world'; | |
$selectedNode = undefined | |
let root = { | |
id : 0, | |
name : 'root', | |
child : [ | |
{ | |
id : 1, | |
name : '1', | |
child : [ | |
{ | |
id : 2, | |
name : '1.1', | |
child : [ | |
] | |
}, | |
{ | |
id : 3, | |
name : '1.2', | |
child : [ | |
] | |
} | |
] | |
}, | |
{ | |
id : 4, | |
name : '2', | |
child : [ | |
{ | |
id : 5, | |
name : '2.1', | |
child : [ | |
] | |
}, | |
{ | |
id : 6, | |
name : '2.2', | |
child : [ | |
] | |
} | |
] | |
} | |
] | |
} | |
let accessor = (x) => { | |
if (x.child != undefined && x.child != null && Array.isArray(x.child)) { | |
return x.child; | |
} | |
return []; | |
} | |
let nodeId = (x) => x.id; | |
let nodefilter = (node, search) => { | |
if (search === undefined || search === null || search == '') { | |
return node; | |
} | |
var children = accessor(node); | |
if (children.length > 0) { | |
var filtered = children.map(x => nodefilter(x, search)).filter(x => x!= null); | |
if ( node.name.includes(search)) { | |
return node; | |
} | |
else if (filtered.length > 0) { | |
return {name:node.name, | |
id:node.id, | |
child:filtered | |
}; | |
} | |
return null; | |
} | |
else { | |
if (node.name.includes(search)) { | |
return node; | |
} | |
return null; | |
} | |
} | |
$: { | |
console.log(selectedNode); | |
} | |
</script> | |
{#if $selectedNode} | |
<h1>clicked : id:>{$selectedNode.id}< - name:>{$selectedNode.name}<</h1> | |
{/if} | |
<TreeView selectable root={root} childrenAccessor={accessor} nodeTemplate={Node} filter={nodefilter} {nodeId}></TreeView> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import App from './App.svelte'; | |
var app = new App({ | |
target: document.body | |
}); | |
export default app; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
import {selectedNode} from './teststore.js' | |
export let data; | |
function clickNode(e) { | |
e.preventDefault(); // avoid deploy/collapse node when clicking node name | |
$selectedNode = data; | |
console.log(data); | |
} | |
</script> | |
<span style='cursor:pointer' role="link" tabindex={data.id} on:click={clickNode} on:keydown={clickNode}>id:>{data.id}< - name:>{data.name}<</span> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { writable } from 'svelte/store'; | |
export const selectedNode = writable({}); | |
selectedNode.subscribe((selection) => { | |
}); | |
selectedNode.update((selection) => selection); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
import {onMount} from "svelte"; | |
import {setContext} from 'svelte'; | |
import TreeViewNode from "./TreeViewNode.svelte"; | |
export let root = {}; | |
export let nodeTemplate; | |
export let childrenAccessor; | |
export let filter = null; | |
export let nodeId; | |
export let selectable; | |
let search; | |
let currentRoot; | |
let selection = {} | |
let selectNode = (selectedNode, selected) => { | |
selection[nodeId(selectedNode)] = selected; | |
} | |
let getNodeSelection = () => selection; | |
let isNodeSelected = (node) => { | |
id = nodeId(node); | |
if (selection.hasOwnProperty(id)) { | |
return selection[id] | |
} | |
return false; | |
} | |
setContext('selectNode', selectNode); | |
setContext('getNodeSelection', getNodeSelection); | |
setContext('isNodeSelected', isNodeSelected); | |
$:{ | |
console.log(selection); | |
search = search; | |
if (filter) { | |
currentRoot = filter(root, search); | |
} | |
} | |
onMount(async () => { | |
currentRoot = root; | |
}) | |
</script> | |
<!-- TODO : add filter --> | |
<input type="text" bind:value={search}/> | |
<TreeViewNode {nodeId} {selectable} node={currentRoot} nodeTemplate={nodeTemplate} childAccessor={childrenAccessor}/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<style> | |
.treemargin { | |
margin-left: 25px; | |
} | |
summary { | |
display: block; | |
} | |
/* Create a new custom triangle on the right side */ | |
summary::before { | |
margin-left: 1ch; | |
display: inline-block; | |
content: '↘️'; | |
transition: 0.2s; | |
} | |
details[open] > summary::before { | |
transform: rotate(180deg); | |
} | |
.leaf::before { | |
content: '🌿' | |
} | |
</style> | |
<script> | |
import {onMount} from "svelte"; | |
import {getContext} from 'svelte'; | |
export let node; | |
export let nodeTemplate; | |
export let childAccessor; | |
export let nodeId; | |
export let selectable; | |
export let selected = false; | |
let child; | |
let isNode; | |
let getNodeSelection = getContext('getNodeSelection'); | |
let selectNode = getContext('selectNode'); | |
let isNodeselected = getContext('isNodeSelected'); | |
onMount(async () => { | |
child = childAccessor(node); | |
isNode = child && Array.isArray(child) && child.length > 0; | |
}) | |
const handleSelect = () => { | |
console.log(`${nodeId(node)} :: ${selected}`) | |
selectNode(node,selected); | |
} | |
</script> | |
{#if isNode} | |
<details class="treemargin" style="text-align: left"> | |
<summary > | |
{#if selectable} | |
<input type="checkbox" bind:value={selected} on:change={handleSelect}/> | |
{/if} | |
<svelte:component this={nodeTemplate} data={node}/> | |
</summary> | |
{#each node.child as subNode} | |
<svelte:self {selectable} {nodeId} node={subNode} {nodeTemplate} childAccessor={childAccessor}/> | |
{/each} | |
</details> | |
{:else} | |
<div class="treemargin leaf"> | |
{#if selectable} | |
<input type="checkbox" bind:checked={selected} on:change={handleSelect}/> | |
{/if} | |
<svelte:component this={nodeTemplate} data={node}/> | |
</div> | |
{/if} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment