Library to show Javascript objects in a nice tree layout. It's written in Svelte but since it compiles to pure JS it can be used anywhere (although to customize the rendered nodes you must Svelte).
npm i svelte-tree-view
How to use
At one point there were some issues packaging this library with SvelteKit, partly because it's written in TypeScript. Now the only extra config that I'm aware you must add is for ensuring you import the library using "svelte" entry point, not "main" or "module" eg:
import nodeResolve from 'rollup-plugin-node-resolve'
...
export default {
...
plugins: [
nodeResolve({
browser: true,
mainFields: ['svelte', 'module', 'browser', 'main'],
dedupe: ['svelte']
}),
],
...
}
To use it:
import TreeView from 'svelte-tree-view'
...
<TreeView
data={selectedEntry.contentDiff}
showLogButton
showCopyButton
valueComponent={DiffValue}
recursionOpts={{
maxDepth: 16,
mapChildren: mapDocDeltaChildren,
shouldExpandNode: () => true
}}
/>
Or if you are not using Svelte (NOTE: if you're using TS you must install svelte as a devDependency for the types):
import { TreeView } from 'svelte-tree-view'
import 'svelte-tree-view/dist/index.css'
const treeView = new TreeView({
target: document.querySelector('#mount-point') as HTMLElement,
props: {
data: {
a: [1, 2, 3],
b: new Map([
['c', { d: null }],
['e', { f: [9, 8, 7] }],
]),
},
recursionOpts: {
maxDepth: 4,
},
},
})
To override default styles I suggest using child or element selector to get enough specificity:
<div class="wrapper">
<TreeView />
</div>
<style>
.wrapper > :global(.svelte-tree-view) {
...;
}
/* OR */
:global(ul.svelte-tree-view) {
...;
}
</style>
API
The full typings as copied from the source are:
export type ValueType =
| 'array'
| 'map'
| 'set'
| 'date'
| 'object'
| 'function'
| 'string'
| 'number'
| 'bigint'
| 'boolean'
| 'symbol'
| 'null'
| 'undefined'
export interface TreeNode<T = any> {
id: string
index: number
key: string
value: T
depth: number
collapsed: boolean
type: ValueType
path: number[]
parentId: string | null
circularOfId: string | null
children: TreeNode[]
}
export interface Base16Theme {
scheme?: string
author?: string
base00: string
base01: string
base02: string
base03: string
base04: string
base05: string
base06: string
base07: string
base08: string
base09: string
base0A: string
base0B: string
base0C: string
base0D: string
base0E: string
base0F: string
}
export type ValueComponent = new (...args: any) => SvelteComponentTyped<{
node: TreeNode
defaultFormatter?: (val: any) => string | undefined
}>
export interface TreeViewProps {
data: unknown
class?: string
theme?: Base16Theme
showLogButton?: boolean
showCopyButton?: boolean
valueComponent?: ValueComponent
recursionOpts?: TreeRecursionOpts
valueFormatter?: (val: any, n: TreeNode) => string | undefined
}
export interface TreeRecursionOpts {
maxDepth?: number
omitKeys?: string[]
stopCircularRecursion?: boolean
isCircularNode?: (n: TreeNode, iteratedValues: Map<any, TreeNode>) => boolean
shouldExpandNode?: (n: TreeNode) => boolean
mapChildren?: (val: any, type: ValueType, parent: TreeNode) => [string, any][] | undefined
}
export class TreeView extends SvelteComponentTyped<TreeViewProps> {}
export default TreeView
Theming
This library uses base16 theming, similar to react-json-tree. So basically instead of theming each type (string, number, undefined etc) separately, you use the same color for all similar values. Here's a repo that might explain it better https://github.com/chriskempson/base16
The example theme is the monokai theme from react-json-tree with changed background color. You can define your own theme or use one from for example here https://github.com/reduxjs/redux-devtools/tree/75322b15ee7ba03fddf10ac3399881e302848874/src/react/themes
To use a theme, you can either provide an object or set CSS variables (recommended).
So either
const theme = {
scheme: 'google',
author: 'seth wright (http://sethawright.com)',
base00: '#1d1f21',
base01: '#282a2e',
base02: '#373b41',
base03: '#969896',
base04: '#b4b7b4',
base05: '#c5c8c6',
base06: '#e0e0e0',
base07: '#ffffff',
base08: '#CC342B',
base09: '#F96A38',
base0A: '#FBA922',
base0B: '#198844',
base0C: '#3971ED',
base0D: '#3971ED',
base0E: '#A36AC7',
base0F: '#3971ED'
}
<div class="wrapper">
<TreeView theme={theme} />
</div>
or
.wrapper {
--tree-view-base00: #363755;
--tree-view-base01: #604d49;
--tree-view-base02: #6d5a55;
--tree-view-base03: #d1929b;
--tree-view-base04: #b79f8d;
--tree-view-base05: #f9f8f2;
--tree-view-base06: #f7f4f1;
--tree-view-base07: #faf8f5;
--tree-view-base08: #fa3e7e;
--tree-view-base09: #fd993c;
--tree-view-base0A: #f6bf81;
--tree-view-base0B: #b8e248;
--tree-view-base0C: #b4efe4;
--tree-view-base0D: #85d9ef;
--tree-view-base0E: #be87ff;
--tree-view-base0F: #d6724c;
}
works.
Other
A little explanation on the internal logic.
Caveats
Rendering very large trees is not fast. The same happens with say react-json-tree but I assume that by using some clever hacks you could make it faster. Like VSCode fast. In general, it seems the use of recursive components is non-optimal regardless of the framework.
How to develop locally
You must have yarn installed globally.
yarn
yarn start
This should start the example-app at http://localhost:3000 that hot-reloads changes to the library inside core
.
NOTE: Since I'm using svelte-kit package
command to build the library it uses the "exports"
of package.json
to make importing the package from Svelte app as efficient as possible. However, in development I'm doing this trick of manually setting the exports to ".": "./src/lib/index.ts"
which enables the example-app to auto-import the changes without having to constantly package the app. It's a bit hackish but hey, it works really well and avoids having to use package
in development completely!
Similar libraries
While this library was basically written from scratch, its UI and API borrows from some existing libraries.
Contributing
PRs & issues are welcome!