Skip to content

KeenMate/web-treeview

Repository files navigation

TreeView Web Component

npm version License: MIT

A framework-agnostic web component wrapper for @keenmate/svelte-treeview. This component allows you to use the powerful Svelte TreeView in any web framework including React, Vue, Angular, or vanilla JavaScript.

Note: This is a wrapper around the original Svelte TreeView component. For comprehensive documentation about features, search options, and advanced configurations, please refer to the Svelte TreeView documentation.

✨ Features

  • 🌐 Framework Agnostic: Works with React, Vue, Angular, or vanilla JavaScript
  • πŸ” Full-text Search: Built-in search with FlexSearch integration
  • 🎯 Drag & Drop: Native drag and drop support with customizable handlers
  • 🎨 Custom Templates: Flexible template system using slots or functions
  • πŸ“± Responsive: Mobile-friendly with touch support
  • ⚑ Performance: Virtual scrolling for large datasets
  • 🎭 TypeScript: Full TypeScript support with type definitions
  • 🧩 Extensible: Rich API with events and methods
  • 🎯 Accessible: ARIA compliant and keyboard navigation

πŸ“¦ Installation

npm install @keenmate/svelte-treeview-webcomponent

πŸš€ Quick Start

Vanilla HTML/JavaScript

<!DOCTYPE html>
<html>
<head>
    <script type="module" src="./node_modules/@keenmate/svelte-treeview-webcomponent/dist/web-treeview.js"></script>
</head>
<body>
    <svelte-tree-view 
        id="my-tree"
        id-member="id" 
        path-member="path"
        display-value-member="name"
        expand-level="2">
    </svelte-tree-view>

    <script>
        const tree = document.getElementById('my-tree');
        tree.data = [
            { id: '1', path: '1', name: 'Documents' },
            { id: '2', path: '1.1', name: 'Projects' },
            { id: '3', path: '1.1.1', name: 'Web App' },
            { id: '4', path: '1.1.1.1', name: 'index.html' }
        ];
        
        // Event listeners
        tree.addEventListener('node-clicked', (e) => {
            console.log('Clicked:', e.detail.node.data.name);
        });
    </script>
</body>
</html>

React

import React, { useEffect, useRef } from 'react';
import '@keenmate/svelte-treeview-webcomponent';
import type { SvelteTreeView } from '@keenmate/svelte-treeview-webcomponent';

const MyComponent = () => {
  const treeRef = useRef<SvelteTreeView>(null);

  useEffect(() => {
    if (treeRef.current) {
      treeRef.current.data = [
        { id: '1', path: '1', name: 'Root' },
        { id: '2', path: '1.1', name: 'Child' }
      ];
    }
  }, []);

  return (
    <svelte-tree-view
      ref={treeRef}
      id-member="id"
      path-member="path"
      expand-level={2}
      onNodeClicked={(e) => console.log('Node clicked:', e.detail.node)}
    />
  );
};

Vue 3

<template>
  <svelte-tree-view
    ref="treeRef"
    id-member="id"
    path-member="path"
    :expand-level="2"
    @node-clicked="handleNodeClick"
  />
</template>

<script setup>
import { ref, onMounted } from 'vue';
import '@keenmate/svelte-treeview-webcomponent';

const treeRef = ref();

onMounted(() => {
  treeRef.value.data = [
    { id: '1', path: '1', name: 'Root' },
    { id: '2', path: '1.1', name: 'Child' }
  ];
});

const handleNodeClick = (event) => {
  console.log('Node clicked:', event.detail.node);
};
</script>

Property Naming Convention

Important: This web component automatically converts between JavaScript camelCase properties and HTML kebab-case attributes:

JavaScript Property HTML Attribute Description
idMember id-member Property name for unique identifier
pathMember path-member Property name for hierarchical path
displayValueMember display-value-member Property name for display text
searchValueMember search-value-member Property name for search text
expandLevel expand-level Initial expansion level
scrollHighlightClass scroll-highlight-class CSS class for scroll highlighting

Examples:

<!-- HTML attributes (kebab-case) -->
<svelte-tree-view 
    display-value-member="name"
    expand-level="2"
    scroll-highlight-class="highlight">
</svelte-tree-view>
// JavaScript properties (camelCase)
tree.displayValueMember = 'name';
tree.expandLevel = 2;
tree.scrollHighlightClass = 'highlight';

🎨 Custom Templates

Use HTML templates with slot attributes to customize rendering:

<svelte-tree-view id-member="id" path-member="path">
  <!-- Custom node template -->
  <template slot="node-template">
    <div class="custom-node">
      <span class="icon">\${node.data.type === 'folder' ? 'πŸ“' : 'πŸ“„'}</span>
      <span class="name">\${node.data.name}</span>
      <span class="size">\${node.data.size || ''}</span>
    </div>
  </template>
  
  <!-- Header template -->
  <template slot="tree-header">
    <h3>πŸ“‚ File Explorer</h3>
  </template>
  
  <!-- Empty state template -->
  <template slot="no-data-found">
    <div class="empty-state">No files found πŸ“­</div>
  </template>
</svelte-tree-view>

Or set templates programmatically:

const tree = document.querySelector('svelte-tree-view');

tree.setNodeTemplate((node) => `
  <div class="custom-node">
    <strong>\${node.data.name}</strong>
    <small>\${node.path}</small>
  </div>
`);

πŸ”§ Configuration

Required Attributes

  • id-member: Property name for unique node identifiers
  • path-member: Property name for hierarchical paths (e.g., "1", "1.1", "1.2.3")

Optional Attributes

Attribute Type Default Description
expand-level number 2 Default expansion level
search-text string "" Current search query
tree-path-separator string "." Path separator character
should-toggle-on-node-click boolean true Toggle expansion on click
should-use-internal-search-index boolean true Enable FlexSearch integration
should-display-debug-information boolean false Show debug info

Visual Styling

Attribute Description
selected-node-class CSS class for selected nodes
drag-over-node-class CSS class during drag over
expand-icon-class CSS class for expand icons
collapse-icon-class CSS class for collapse icons
leaf-icon-class CSS class for leaf node icons

🎯 API Methods

const tree = document.querySelector('svelte-tree-view');

// Expansion control
await tree.expandNodes('1.2');      // Expand specific path
await tree.collapseNodes('1.2');    // Collapse specific path
tree.expandAll();                    // Expand all nodes
tree.collapseAll();                  // Collapse all nodes

// Search and filtering
tree.filterNodes('search term');    // Filter visible nodes
const results = tree.searchNodes('query'); // Get search results

// Navigation
await tree.scrollToPath('1.2.3', {
  behavior: 'smooth',
  block: 'center'
});

// Event handlers
tree.onNodeClicked = (node) => console.log('Clicked:', node);
tree.onNodeDragStart = (node, event) => console.log('Drag start:', node);
tree.onNodeDragOver = (node, event) => console.log('Drag over:', node);
tree.onNodeDrop = (dropNode, draggedNode, event) => {
  console.log('Dropped:', draggedNode, 'on:', dropNode);
};

πŸŽͺ Events

Listen for custom events:

tree.addEventListener('node-clicked', (e) => {
  console.log('Node clicked:', e.detail.node);
});

tree.addEventListener('selected-node-changed', (e) => {
  console.log('Selection changed:', e.detail.selectedNode);
});

tree.addEventListener('search-text-changed', (e) => {
  console.log('Search changed:', e.detail.searchText);
});

tree.addEventListener('node-drag-start', (e) => {
  console.log('Drag started:', e.detail.node, e.detail.event);
});

tree.addEventListener('node-drop', (e) => {
  console.log('Node dropped:', e.detail.node, e.detail.draggedNode);
});

πŸ—„οΈ Data Format

The component expects hierarchical data using LTree-style paths:

const data = [
  {
    id: '1',           // Unique identifier
    path: '1',         // Hierarchical path
    name: 'Documents', // Display name
    // ... custom properties
  },
  {
    id: '2',
    path: '1.1',       // Child of '1'
    name: 'Projects',
  },
  {
    id: '3',
    path: '1.1.1',     // Child of '1.1'
    name: 'Web App',
  },
  {
    id: '4',
    path: '1.2',       // Another child of '1'
    name: 'Images',
  }
];

🎨 Styling

The component includes default styles but can be customized:

/* Custom CSS variables */
svelte-tree-view {
  --tree-indent: 20px;
  --node-height: 32px;
  --selected-bg: #e3f2fd;
  --hover-bg: #f5f5f5;
  --icon-size: 16px;
  --font-size: 14px;
}

/* Custom node styling */
svelte-tree-view .custom-node {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px;
  border-radius: 4px;
}

svelte-tree-view .custom-node:hover {
  background-color: var(--hover-bg);
}

πŸ“š Examples

Check out the examples/ directory for complete implementations:

Relationship to Svelte TreeView

This web component is a wrapper around @keenmate/svelte-treeview. It provides:

  • βœ… Framework-agnostic interface via web components
  • βœ… Shadow DOM encapsulation for style isolation
  • βœ… HTML attribute ↔ JavaScript property conversion (kebab-case ↔ camelCase)
  • βœ… Template slot β†’ Svelte snippet conversion
  • βœ… Custom event dispatching for framework integration

For detailed documentation about the underlying TreeView features, search options, advanced configurations, and all available properties, please refer to the Svelte TreeView documentation.

Key differences from direct Svelte usage:

  1. Attributes: Use kebab-case HTML attributes instead of camelCase props
  2. Data binding: Set data property programmatically instead of binding
  3. Events: Listen for CustomEvents instead of component events
  4. Templates: Use HTML <template slot="..."> instead of Svelte snippets

🀝 Contributing

Contributions are welcome! Please read the contributing guide for details.

πŸ“„ License

MIT License - see LICENSE for details.

πŸ”— Related Projects

πŸ†˜ Support


Made with ❀️ by KeenMate

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •