JSFiddle - React, Tailwind, and code Playground

by WILLIAM CORREA

HTML

<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
<!-- item template -->
<script type="text/x-template" id="item-template">
  <li>
    <div :class="{bold: isFolder}" @click="toggle" @dblclick="changeType">
      {{model.name}}
      <span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
    </div>
    <ul v-show="open" v-if="isFolder">
      <item v-for="_node in children" class="item"
        :key="$parent.$index" :model="_node" :filterterm="filterterm">
      </item>
    </ul>
  </li>
</script>

<p>(You can double click on an item to turn it into a folder.)</p>

<!-- the demo root element -->
<ul id="demo">
  <input type="search" placeholder="Filtrar" v-on:input="filterterm = $event.target.value"/>
  <item class="item" :model="treeData" :filterterm="filterterm"/>
</ul>

CSS

body {
  font-family: Menlo, Consolas, monospace;
  color: #444;
}
.item {
  cursor: pointer;
}
.bold {
  font-weight: bold;
}
ul {
  padding-left: 1em;
  line-height: 1.5em;
  list-style-type: dot;
}

Babel + JSX

// demo data
var data = {
  name: 'My Tree',
  children: [
    { name: 'hello' },
    { name: 'wat' },
    {
      name: 'child folder 1',
      children: [
        {
          name: 'child folder 2',
          children: [
            { name: 'hello' },
            { name: 'wat' }
          ]
        },
        { name: 'hello' },
        { name: 'wat' },
        {
          name: 'child folder 3',
          children: [
            { name: 'hello' },
            { name: 'wat 123' }
          ]
        }
      ]
    },{
    	name: 'child folder 1.1',
      children: [
        {
          name: 'child folder 2',
          children: [
            { name: 'hello' },
            { name: 'wat 456' }
          ]
        }
      ]
    }
  ]
}

// define the item component
Vue.component('item', {
  template: '#item-template',
  props: {
    model: Object,
    filterterm: String 
  },
  data: function () {
    return {
      open: true
    }
  },
  computed: {
  	isFolder () {
    	return this.model.children;
    },
    children () {
    	const filter = (object) => {
        return object.name === 'wat 456' ||
               object.children && (object.children = object.children.filter(filter)).length
      }
    	return this.model.children.filter(filter)
    }
  },
  methods: {
    toggle: function () {
      if (this.isFolder) {
        this.open = !this.open
      }
    },
    changeType: function () {
      if (!this.isFolder) {
        Vue.set(this.model, 'children', [])
        this.addChild()
        this.open = true
      }
    }
  }
})

// boot up the demo
var demo = new Vue({
  el: '#demo',
  data: {
    treeData: data,
    filterterm: ''
  }
})