Coder Social home page Coder Social logo

kcsujeet / sl-vue-tree-next Goto Github PK

View Code? Open in Web Editor NEW

This project forked from holiber/sl-vue-tree

4.0 0.0 1.0 884 KB

Customizable draggable tree component for Vue.js 3

License: MIT License

JavaScript 31.88% CSS 4.75% Vue 54.88% HTML 1.15% TypeScript 7.34%

sl-vue-tree-next's Introduction

sl-vue-tree-next

Vue3 supported version of sl-vue-tree. A customizable draggable tree component for Vue.js.

preview

demo

install

npm i sl-vue-tree-next

Quick start

<template>
    <h2>Vue 3 Tree</h2>
    <sl-vue-tree-next v-model="nodes" />

</template>

<script setup lang="ts">
import { SlVueTreeNext } from 'sl-vue-tree-next'

const nodes = [
    { title: 'Item1', isLeaf: true },
    { title: 'Item2', isLeaf: true, data: { visible: false } },
    { title: 'Folder1' },
    {
        title: 'Folder2',
        isExpanded: true,
        children: [
            { title: 'Item3', isLeaf: true },
            { title: 'Item4', isLeaf: true },
            {
                title: 'Folder3',
                children: [{ title: 'Item5', isLeaf: true }],
            },
        ],
    },
    { title: 'Folder5', isExpanded: false },
    { title: 'Item6', isLeaf: true },
    { title: 'Item7', isLeaf: true, data: { visible: false } },
    {
        title: 'Folder6',
        children: [
            {
                title: 'Folder7',
                children: [
                    { title: 'Item8', isLeaf: true },
                    { title: 'Item9', isLeaf: true },
                ],
            },
        ],
    },
]
</script>

<style>
  @import 'sl-vue-tree-next/sl-vue-tree-next-minimal.css';
</style>

You can also use dark version.

<style>
  @import 'sl-vue-tree-next/sl-vue-tree-next-dark.css';
</style>

The value property is an array of NodeModel nodes:

interface NodeModel<TDataType> {
    title: string;
    isLeaf?: boolean;
    children?: NodeModel<TDataType>[];
    isExpanded?: boolean;
    isSelected?: boolean;
    isDraggable?: boolean;
    isSelectable?: boolean;
    data?: TDataType; // any serializable user data
}

For convenience the component's events return Node objects. Those actually are NodeModel with some computed props:

interface TreeNode<TDataType> extends NodeModel<TDataType> {
    isFirstChild: boolean;
    isLastChild: boolean;
    isVisible: boolean;	// node is visible if all of its parents are expanded
    level: number; // nesting level
    ind: number; // index in the array of siblings
    path: number[]; // path to node as array of indexes, for example [2, 0, 1] in the example above is path to `Item4`
    pathStr: string; // serialized path to node
    children: TreeNode<TDataType>[];
}

You can get the list of Node from the computed slVueTree.currentNodes property

Props

prop type default description
value NodeModel[] [] An array of nodes to show. Each node is represented by NodeModel interface
allowMultiselect Boolean true Disable or enable the multiselect feature
allowToggleBranch Boolean true Disable or enable the expand/collapse button
edgeSize Number 3 Offset in pixels from top and bottom for folder-node element. While dragging cursor is in that offset, the dragging node will be placed before or after the folder-node instead of being placed inside the folder.
scrollAreaHeight Number 70 Offset in pixels from top and bottom for the component element. While dragging cursor is in that area, the scrolling starts.
maxScrollSpeed Number 20 The scroll speed is relative to the cursor position. Defines the max scroll speed.
multiselectKey String/String[] ['ctrlKey', 'metaKey'] The keys for multiselect mode. Allowed values are ['ctrlKey', 'metaKey', 'altKey']

Computed props

prop type description
currentNodes TreeNode[] List of nodes with some computed props. See Node interface.
cursorPosition ICursorPosition Represents the current cursor position that describes the action that will be applied to the dragged node on mouseup event. See ICursorPosition interface
selectionSize Number The count of selected nodes
dragSize Number The count of selected and draggable nodes
isDragging Boolean True if nodes are dragging
interface ICursorPosition<TDataType> {
  node: Node<TDataType>;
  placement: 'before' | 'inside' | 'after';
}

Events

event callback arguments description
input nodes: NodeModel[] triggers for any changes to value property
select selectedNodes: TreeNode[], event: MouseEvent triggers when a node has been selected/deselected
toggle toggledNode: TreeNode, event: MouseEvent triggers when a node has been collapsed/expanded
drop draggingNodes: TreeNode[], position: ICursorPosition, event: MouseEvent triggers when dragging nodes have been dropped
nodeclick node: TreeNode, event: MouseEvent handle click event on node
nodedblclick node: TreeNode, event: MouseEvent handle dblclick event on node
nodecontextmenu node: TreeNode, event: MouseEvent handle contextmenu event on node
externaldrop cursorPosition: ICursorPosition, event: MouseEvent handle drop event for external items demo

Methods

method description
getNode(path: number[]): TreeNode Find the node by using its path
traverse(cb: (node: TreeNode, nodeModel: NodeModel, siblings: NodeModel[]) => boolean) Helpful method to traverse all nodes. The traversing will be stopped if callback returns false.
updateNode({ path: number[], patch: Partial }) Update the node by using its path
select(path: number[], addToSelection = false) Select the node by using its path
getNodeEl(): HTMLElement Get the node HTMLElement by using its path
getSelected(): TreeNode[] Get selected nodes
insert(position: ICursorPosition, nodeModel: NodeModel) Insert nodes by the current cursor position.
remove(paths: number[][]) Remove nodes by paths. For example .remove([[0,1], [0,2]])
getFirstNode(): TreeNode Get the first node in the tree
getLastNode(): TreeNode Get the last node in the tree
getNextNode(path: number[], filter?: (node: TreeNode) => boolean): TreeNode; Get the next node. You can skip the next nodes by using filter
getPrevNode(path: number[], filter?: (node: TreeNode) => boolean): TreeNode; Get the previous node. You can skip the previous nodes by using filter

Slots

slot context description
title TreeNode Slot for item title
toggle TreeNode Slot for expand/collapse button
sidebar TreeNode Sidebar content
draginfo SlVueTree Slot that follows the mouse cursor while dragging. By default shows the dragging nodes count.
empty-node TreeNode Slot for (optional) message when folder is open, but empty

Examples

Add a folder or item icon via title slot

<sl-vue-tree-next v-model="nodes">
    <template #title="{ node }">

      <span class="item-icon">
        <i class="fa fa-file" v-if="node.isLeaf"></i>
        <i class="fa fa-folder" v-if="!node.isLeaf"></i>
      </span>

      {{ node.title }}

    </template>
</sl-vue-tree-next>

Select all nodes

slVueTree.traverse((node, nodeModel, path) => {
    Vue.set(nodeModel, 'isSelected', true);
})

Handle keydown and keyup events via getNextNode and getPrevNode methods

Contributing

see CONTRIBUTING.md

Changelog

v0.0.13

  • fixes duplicate node issue when moving multiple nodes
  • uses deep merge to update node when using updateNode function
  • fixes dark mode toggle button in demo

v0.0.12

  • fixes wrong defineComponent not defined issue

v0.0.11

  • fixes keyboard control issues
  • exposes maxScrollSpeed and scrollAreaHeight as props
  • exposes selectionSize to ref

v0.0.10

  • fixes lower level icons not appearing bug
  • fixes node update bug

v0.0.9

  • update demo
  • update readme

v0.0.8

  • update demos

v0.0.7

  • add support for generics

v0.0.6

  • update readme.md

v0.0.5

  • fix computed warnings in console
  • fixed duplicate nodes bug

v0.0.4

  • made minimal and dark css available

v0.0.3

  • removed vue from dependency and added to peer dependency

v0.0.2

  • added type safety to props and methods

v0.0.1

  • migrated to vue 3

sl-vue-tree-next's People

Contributors

holiber avatar kcsujeet avatar onekiloparsec avatar lazylester avatar shibukk avatar alex-sokolov avatar rojtjo avatar yuki-inoue avatar darrelfrancis avatar ericksonc avatar opowell avatar

Stargazers

陶锅煮新茄子 avatar Shaobo Lua avatar King Judd avatar  avatar

Forkers

mayank30

sl-vue-tree-next's Issues

Is it possible to stop dragging node after dragging is initiated?

I would like to be able to grab nodes, but not drop them in certain cases. Is it possible to stop the event before dropping the Node and reverse the tree like it was before?
I am currently resetting the tree to a previous state if the drop is not needed.

I have tried the followings: set @beforedrop and @drop to false; set the given node's isDraggable to false during @beforedrop but neither seemed to be working.
I have also tried to set @drop.prevent but I have received Uncaught TypeError: e.preventDefault is not a function error.

Moving multiple layers

When moving multiple layers, it duplicates child nodes at the location of parent nodes. As it is difficult do clearly describe I will add a video recording.

Cause of this: the program moves each highlighted node to the target location, ignoring that it has been already moved via its parent.

Suggestion for avoiding this: when moving multiple nodes check for each node weather its parent moved. If parent moved, ignore the child's movement.

Screencast.from.2024-03-14.11.44.38.webm

File-tree based path

Is it possible to easily get file-tree-based path of a node?
My current solution is the following:

function getFilePathByLocation(node){
    let newNamebaseTreePath = "."
    let currentslVueTreePath = []
    node.path.forEach((pathElement) =>{
        currentslVueTreePath.push(pathElement)
        newNamebaseTreePath += "/"+ slVueTree.value.select(currentslVueTreePath).title
    })
    return newNamebaseTreePath
}

This does not work for @drop=<myOnDropFunction>, as the slVueTree reference changes before <myOnDropFunction> is called, which makes it quite difficult to reverse-engineer the original position of nodes before the moving operation. This is especially true, when dropping multiple nodes.

Undefined 'defineComponent'

With v0.0.11 I have received the following error, which is not present is v0.0.10:

Uncaught TypeError: Cannot read properties of undefined (reading 'defineComponent')

The error points to the following row:
var Ue = window.Vue.defineComponent;
which can be found at the following location:
node_modules/.vite/deps/sl-vue-tree-next.js

Here is my package.json if needed:

{
  "name": "vue-web",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@codemirror/lang-json": "^6.0.1",
    "@codemirror/lang-markdown": "^6.2.4",
    "@codemirror/lang-python": "^6.1.4",
    "@codemirror/legacy-modes": "^6.3.3",
    "codemirror": "^6.0.1",
    "pinia": "^2.1.7",
    "primeflex": "^3.3.1",
    "primeicons": "^6.0.1",
    "primevue": "^3.49.1",
    "sl-vue-tree-next": "^0.0.11",
    "vue": "^3.4.15",
    "vue-codemirror6": "^1.2.5",
    "vue-router": "^4.2.5",
    "vue-upload-component": "^3.1.8"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.3",
    "vite": "^5.0.11"
  }
}

Whole data property is overridden on updateNode

When using updateNode() to override data of a node, it overrides the whole data, instead of only a specific part of it.

Example code:

    slVueTree.value.updateNode({path:selectedNode.path, patch:{data: {renameNode : true}}});
    console.log(slVueTree.value.getNode(selectedNode.path));
    slVueTree.value.updateNode({path:selectedNode.path, patch:{data: {realLocation : true}}});
    console.log(slVueTree.value.getNode(selectedNode.path));

Based on the console messages, the data field looses the renameNode field when adding realLocation.

Certain props are not available

It seems that mutliselectKey prop is not assignable. I am not sure, about this, but I think SlVueTreeNext.vue.d.ts file has the assignable props. If this is correct, scrollAreaHeight and maxScrollSpeed are not assignable either.
Although edgeSize is assignable, it does not seem to do anything.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.