mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 12:14:41 +01:00
feat(Tree): new component (#3180)
Co-authored-by: hywax <me@hywax.space> Co-authored-by: Benjamin Canac <canacb1@gmail.com> Co-authored-by: Sébastien Chopin <atinux@gmail.com> Co-authored-by: Sébastien Chopin <seb@nuxt.com>
This commit is contained in:
@@ -316,7 +316,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
|
||||
<template>
|
||||
<div class="my-5">
|
||||
<div>
|
||||
<div v-if="options.length" class="flex items-center gap-2.5 border border-(--ui-border-muted) border-b-0 relative rounded-t-[calc(var(--ui-radius)*1.5)] px-4 py-2.5 overflow-x-auto">
|
||||
<div v-if="options.length" class="flex flex-wrap items-center gap-2.5 border border-(--ui-border-muted) border-b-0 relative rounded-t-[calc(var(--ui-radius)*1.5)] px-4 py-2.5 overflow-x-auto">
|
||||
<template v-for="option in options" :key="option.name">
|
||||
<UFormField
|
||||
:label="option.label"
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import type { TreeItem } from '@nuxt/ui'
|
||||
|
||||
const items: TreeItem[] = [
|
||||
{
|
||||
label: 'app/',
|
||||
slot: 'app',
|
||||
defaultExpanded: true,
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTree :items="items">
|
||||
<template #app="{ item }">
|
||||
<p class="italic font-bold">
|
||||
{{ item.label }}
|
||||
</p>
|
||||
</template>
|
||||
</UTree>
|
||||
</template>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import type { TreeItem } from '@nuxt/ui'
|
||||
|
||||
const items: TreeItem[] = [
|
||||
{
|
||||
label: 'app/',
|
||||
value: 'app',
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
value: 'composables',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
value: 'components',
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
]
|
||||
|
||||
const expanded = ref(['app', 'composables'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTree v-model:expanded="expanded" :items="items" />
|
||||
</template>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import type { TreeItem } from '@nuxt/ui'
|
||||
|
||||
const items: TreeItem[] = [
|
||||
{
|
||||
label: 'app/',
|
||||
defaultExpanded: true,
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
]
|
||||
|
||||
const value = ref(items[items.length - 1])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTree v-model="value" :items="items" />
|
||||
</template>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import type { TreeItem } from '@nuxt/ui'
|
||||
|
||||
const items: TreeItem[] = [
|
||||
{
|
||||
label: 'app/',
|
||||
defaultExpanded: true,
|
||||
onSelect: (e: Event) => {
|
||||
e.preventDefault()
|
||||
},
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTree :items="items" />
|
||||
</template>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import type { TreeItem } from '@nuxt/ui'
|
||||
|
||||
const items: TreeItem[] = [
|
||||
{
|
||||
label: 'app/',
|
||||
defaultExpanded: true,
|
||||
onToggle: (e: Event) => {
|
||||
e.preventDefault()
|
||||
},
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTree :items="items" />
|
||||
</template>
|
||||
436
docs/content/3.components/tree.md
Normal file
436
docs/content/3.components/tree.md
Normal file
@@ -0,0 +1,436 @@
|
||||
---
|
||||
description: A tree view component to display and interact with hierarchical data structures.
|
||||
category: data
|
||||
links:
|
||||
- label: Tree
|
||||
icon: i-custom-reka-ui
|
||||
to: https://www.reka-ui.com/components/tree.html
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/Tree.vue
|
||||
navigation.badge: Soon
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Items
|
||||
|
||||
Use the `items` prop as an array of objects with the following properties:
|
||||
|
||||
- `icon?: string`{lang="ts-type"}
|
||||
- `label?: string`{lang="ts-type"}
|
||||
- `trailingIcon?: string`{lang="ts-type"}
|
||||
- `defaultExpanded?: boolean`{lang="ts-type"}
|
||||
- `disabled?: boolean`{lang="ts-type"}
|
||||
- `value?: string`{lang="ts-type"}
|
||||
- `slot?: string`{lang="ts-type"}
|
||||
- `children?: TreeItem[]`{lang="ts-type"}
|
||||
- `onToggle?(e: Event): void`{lang="ts-type"}
|
||||
- `onSelect?(e?: Event): void`{lang="ts-type"}
|
||||
|
||||
::note
|
||||
A unique identifier is required for each item. The component will use the `value` prop as identifier, falling back to `label` if `value` is not provided. One of these must be provided for the component to work properly.
|
||||
::
|
||||
|
||||
::component-code
|
||||
---
|
||||
collapse: true
|
||||
hide:
|
||||
- class
|
||||
ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
items:
|
||||
- label: 'app/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'composables/'
|
||||
children:
|
||||
- label: 'useAuth.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'useUser.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'components/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'Card.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'Button.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'app.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'nuxt.config.ts'
|
||||
icon: 'i-vscode-icons-file-type-nuxt'
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
### Multiple
|
||||
|
||||
Use the `multiple` prop to allow multiple item selections.
|
||||
|
||||
::component-code
|
||||
---
|
||||
collapse: true
|
||||
hide:
|
||||
- class
|
||||
ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
multiple: true
|
||||
items:
|
||||
- label: 'app/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'composables/'
|
||||
children:
|
||||
- label: 'useAuth.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'useUser.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'components/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'Card.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'Button.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'app.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'nuxt.config.ts'
|
||||
icon: 'i-vscode-icons-file-type-nuxt'
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
### Color
|
||||
|
||||
Use the `color` prop to change the color of the Tree.
|
||||
|
||||
::component-code
|
||||
---
|
||||
collapse: true
|
||||
hide:
|
||||
- class
|
||||
ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
color: neutral
|
||||
items:
|
||||
- label: 'app/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'composables/'
|
||||
children:
|
||||
- label: 'useAuth.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'useUser.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'components/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'Card.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'Button.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'app.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'nuxt.config.ts'
|
||||
icon: 'i-vscode-icons-file-type-nuxt'
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
### Size
|
||||
|
||||
Use the `size` prop to change the size of the Tree.
|
||||
|
||||
::component-code
|
||||
---
|
||||
collapse: true
|
||||
hide:
|
||||
- class
|
||||
ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
size: xl
|
||||
items:
|
||||
- label: 'app/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'composables/'
|
||||
children:
|
||||
- label: 'useAuth.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'useUser.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'components/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'Card.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'Button.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'app.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'nuxt.config.ts'
|
||||
icon: 'i-vscode-icons-file-type-nuxt'
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
### Trailing Icon
|
||||
|
||||
Use the `trailing-icon` prop to customize the trailing [Icon](/components/icon) of a parent node. Defaults to `i-lucide-chevron-down`.
|
||||
|
||||
::note
|
||||
If an icon is specified for an item, it will always take precedence over these props.
|
||||
::
|
||||
|
||||
::component-code
|
||||
---
|
||||
collapse: true
|
||||
hide:
|
||||
- class
|
||||
ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
trailingIcon: 'i-lucide-arrow-down'
|
||||
items:
|
||||
- label: 'app/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'composables/'
|
||||
trailingIcon: 'i-lucide-chevron-down'
|
||||
children:
|
||||
- label: 'useAuth.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'useUser.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'components/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'Card.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'Button.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'app.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'nuxt.config.ts'
|
||||
icon: 'i-vscode-icons-file-type-nuxt'
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
::framework-only
|
||||
#nuxt
|
||||
:::tip{to="/getting-started/icons/nuxt#theme"}
|
||||
You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key.
|
||||
:::
|
||||
|
||||
#vue
|
||||
:::tip{to="/getting-started/icons/vue#theme"}
|
||||
You can customize this icon globally in your `vite.config.ts` under `ui.icons.chevronDown` key.
|
||||
:::
|
||||
::
|
||||
|
||||
### Expanded Icon
|
||||
|
||||
Use the `expanded-icon` and `collapsed-icon` props to customize the icons of a parent node when it is expanded or collapsed. Defaults to `i-lucide-folder-open` and `i-lucide-folder` respectively.
|
||||
|
||||
::component-code
|
||||
---
|
||||
collapse: true
|
||||
hide:
|
||||
- class
|
||||
ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
expandedIcon: 'i-lucide-book-open'
|
||||
collapsedIcon: 'i-lucide-book'
|
||||
items:
|
||||
- label: 'app/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'composables/'
|
||||
children:
|
||||
- label: 'useAuth.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'useUser.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'components/'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'Card.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'Button.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'app.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'nuxt.config.ts'
|
||||
icon: 'i-vscode-icons-file-type-nuxt'
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
::framework-only
|
||||
#nuxt
|
||||
:::tip{to="/getting-started/icons/nuxt#theme"}
|
||||
You can customize these icons globally in your `app.config.ts` under `ui.icons.folder` and `ui.icons.folderOpen` keys.
|
||||
:::
|
||||
|
||||
#vue
|
||||
:::tip{to="/getting-started/icons/vue#theme"}
|
||||
You can customize these icons globally in your `vite.config.ts` under `ui.icons.folder` and `ui.icons.folderOpen` keys.
|
||||
:::
|
||||
::
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` prop to prevent any user interaction with the Tree.
|
||||
|
||||
::note
|
||||
You can also disable individual items using `item.disabled`.
|
||||
::
|
||||
|
||||
::component-code
|
||||
---
|
||||
collapse: true
|
||||
hide:
|
||||
- class
|
||||
ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
disabled: true
|
||||
items:
|
||||
- label: 'app'
|
||||
icon: 'i-lucide-folder'
|
||||
defaultExpanded: true
|
||||
children:
|
||||
- label: 'composables'
|
||||
icon: 'i-lucide-folder'
|
||||
children:
|
||||
- label: 'useAuth.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'useUser.ts'
|
||||
icon: 'i-vscode-icons-file-type-typescript'
|
||||
- label: 'components'
|
||||
icon: 'i-lucide-folder'
|
||||
children:
|
||||
- label: 'Home'
|
||||
icon: 'i-lucide-folder'
|
||||
children:
|
||||
- label: 'Card.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'Button.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'app.vue'
|
||||
icon: 'i-vscode-icons-file-type-vue'
|
||||
- label: 'nuxt.config.ts'
|
||||
icon: 'i-vscode-icons-file-type-nuxt'
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
## Examples
|
||||
|
||||
### Control selected item(s)
|
||||
|
||||
You can control the selected item(s) by using the `default-value` prop or the `v-model` directive.
|
||||
|
||||
::component-example
|
||||
---
|
||||
name: 'tree-model-value-example'
|
||||
collapse: true
|
||||
props:
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
If you want to prevent an item from being selected, you can use the `item.onSelect()`{lang="ts-type"} property:
|
||||
|
||||
::component-example
|
||||
---
|
||||
name: 'tree-on-select-example'
|
||||
collapse: true
|
||||
props:
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
::note
|
||||
This lets you expand or collapse a parent item without selecting it.
|
||||
::
|
||||
|
||||
### Control expanded items
|
||||
|
||||
You can control the expanded items by using the `default-expanded` prop or the `v-model` directive.
|
||||
|
||||
::component-example
|
||||
---
|
||||
name: 'tree-expanded-example'
|
||||
collapse: true
|
||||
props:
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
If you want to prevent an item from being expanded, you can use the `item.onToggle()`{lang="ts-type"} property:
|
||||
|
||||
::component-example
|
||||
---
|
||||
name: 'tree-on-toggle-example'
|
||||
collapse: true
|
||||
props:
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
::note
|
||||
This lets you select a parent item without expanding or collapsing its children.
|
||||
::
|
||||
|
||||
### With custom slot
|
||||
|
||||
Use the `item.slot` property to customize a specific item.
|
||||
|
||||
::component-example
|
||||
---
|
||||
name: 'tree-custom-slot-example'
|
||||
collapse: true
|
||||
props:
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
:component-props
|
||||
|
||||
### Slots
|
||||
|
||||
:component-slots
|
||||
|
||||
### Emits
|
||||
|
||||
:component-emits
|
||||
|
||||
## Theme
|
||||
|
||||
:component-theme
|
||||
BIN
docs/public/components/dark/tree.png
Normal file
BIN
docs/public/components/dark/tree.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
BIN
docs/public/components/light/tree.png
Normal file
BIN
docs/public/components/light/tree.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
Reference in New Issue
Block a user