-
Notifications
You must be signed in to change notification settings - Fork 584
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9b976a0
commit c3db82e
Showing
11 changed files
with
376 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<template> | ||
<UList> | ||
<div v-for="(item, key) in items" :key="key" class="flex items-center gap-2"> | ||
<UIcon :name="item.icon" /> {{ item.label }} | ||
</div> | ||
|
||
<template #separator-after> | ||
<UDivider class="my-2" /> | ||
</template> | ||
</UList> | ||
</template> | ||
|
||
<script setup> | ||
const items = [ | ||
{ label: 'Home', icon: 'i-heroicons-home' }, | ||
{ label: 'Profile', icon: 'i-heroicons-user-circle' }, | ||
{ label: 'Security', icon: 'i-heroicons-shield-check' }, | ||
{ label: 'Password Reset', icon: 'i-heroicons-key' } | ||
] | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<template> | ||
<UList gap> | ||
<div v-for="(item, key) in items" :key="key" class="rounded bg-gray-200 dark:bg-gray-800 px-2 flex items-center gap-2"> | ||
<UIcon :name="item.icon" /> {{ item.label }} | ||
</div> | ||
|
||
<template #separator-after> | ||
<UDivider class="mt-4" /> | ||
</template> | ||
</UList> | ||
</template> | ||
|
||
<script setup> | ||
const items = [ | ||
{ label: 'Home', icon: 'i-heroicons-home' }, | ||
{ label: 'Users', icon: 'i-heroicons-users' }, | ||
{ label: 'Carts', icon: 'i-heroicons-shopping-bag' }, | ||
{ label: 'Shipments', icon: 'i-heroicons-truck' } | ||
] | ||
</script> |
25 changes: 25 additions & 0 deletions
25
docs/components/content/examples/ListExampleItemOrientation.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<template> | ||
<UList item-orientation="horizontal"> | ||
<template #separator-before="{ index }"> | ||
<div | ||
class="flex items-center text-right text-green-500 pr-1" | ||
:style="`padding-left: ${Math.max(0, index - 1)}em`" | ||
> | ||
<UIcon name="i-heroicons-arrow-uturn-right" class="-scale-y-100" /> | ||
</div> | ||
</template> | ||
|
||
<div v-for="(item, key) in items" :key="key" class="flex items-center gap-2"> | ||
{{ item.label }} | ||
</div> | ||
</UList> | ||
</template> | ||
|
||
<script setup> | ||
const items = [ | ||
{ label: 'Home' }, | ||
{ label: 'Profile' }, | ||
{ label: 'Security' }, | ||
{ label: 'Password Reset' } | ||
] | ||
</script> |
22 changes: 22 additions & 0 deletions
22
docs/components/content/examples/ListExampleOrientation.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<template> | ||
<UList orientation="horizontal"> | ||
<div v-for="(item, key) in items" :key="key" class="flex items-center gap-2"> | ||
{{ item.label }} | ||
</div> | ||
|
||
<template #separator-after> | ||
<div class="flex items-center px-1 text-gray-400 dark:text-gray-600"> | ||
<UIcon name="i-heroicons-chevron-right" /> | ||
</div> | ||
</template> | ||
</UList> | ||
</template> | ||
|
||
<script setup> | ||
const items = [ | ||
{ label: 'Home' }, | ||
{ label: 'Profile' }, | ||
{ label: 'Security' }, | ||
{ label: 'Password Reset' } | ||
] | ||
</script> |
20 changes: 20 additions & 0 deletions
20
docs/components/content/examples/ListExamplePaddingClass.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<template> | ||
<UList class="gap-y-1"> | ||
<div v-for="(item, key) in items" :key="key" class="rounded bg-gray-200 dark:bg-gray-800 px-2 flex items-center gap-2"> | ||
<UIcon :name="item.icon" /> {{ item.label }} | ||
</div> | ||
|
||
<template #separator-after> | ||
<UDivider class="mt-1" /> | ||
</template> | ||
</UList> | ||
</template> | ||
|
||
<script setup> | ||
const items = [ | ||
{ label: 'Home', icon: 'i-heroicons-home' }, | ||
{ label: 'Users', icon: 'i-heroicons-users' }, | ||
{ label: 'Carts', icon: 'i-heroicons-shopping-bag' }, | ||
{ label: 'Shipments', icon: 'i-heroicons-truck' } | ||
] | ||
</script> |
20 changes: 20 additions & 0 deletions
20
docs/components/content/examples/ListExampleSlotSeparatorAfter.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<template> | ||
<UList> | ||
<div v-for="(item, key) in items" :key="key" class="flex items-center gap-2"> | ||
<UIcon :name="item.icon" /> {{ item.label }} | ||
</div> | ||
|
||
<template #separator-after> | ||
<hr class="border-gray-200 dark:border-gray-800 my-2"> | ||
</template> | ||
</UList> | ||
</template> | ||
|
||
<script setup> | ||
const items = [ | ||
{ label: 'Home', icon: 'i-heroicons-home' }, | ||
{ label: 'Profile', icon: 'i-heroicons-user-circle' }, | ||
{ label: 'Security', icon: 'i-heroicons-shield-check' }, | ||
{ label: 'Password Reset', icon: 'i-heroicons-key' } | ||
] | ||
</script> |
20 changes: 20 additions & 0 deletions
20
docs/components/content/examples/ListExampleSlotSeparatorBefore.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<template> | ||
<UList> | ||
<template #separator-before> | ||
<hr class="border-gray-200 dark:border-gray-800 my-2"> | ||
</template> | ||
|
||
<div v-for="(item, key) in items" :key="key" class="flex items-center gap-2"> | ||
<UIcon :name="item.icon" /> {{ item.label }} | ||
</div> | ||
</UList> | ||
</template> | ||
|
||
<script setup> | ||
const items = [ | ||
{ label: 'Home', icon: 'i-heroicons-home' }, | ||
{ label: 'Profile', icon: 'i-heroicons-user-circle' }, | ||
{ label: 'Security', icon: 'i-heroicons-shield-check' }, | ||
{ label: 'Password Reset', icon: 'i-heroicons-key' } | ||
] | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<template> | ||
<UList class="w-64" orientation="horizontal" wrap gap> | ||
<div | ||
v-for="(item, key) in items" | ||
:key="key" | ||
class="w-30 rounded bg-gray-200 dark:bg-gray-800 px-2 flex items-center gap-2" | ||
> | ||
<UIcon :name="item.icon" /> {{ item.label }} | ||
</div> | ||
</UList> | ||
</template> | ||
|
||
<script setup> | ||
const items = [ | ||
{ label: 'Home', icon: 'i-heroicons-home' }, | ||
{ label: 'Users', icon: 'i-heroicons-users' }, | ||
{ label: 'Carts', icon: 'i-heroicons-shopping-bag' }, | ||
{ label: 'Shipments', icon: 'i-heroicons-truck' } | ||
] | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
--- | ||
description: Create horizontal o vertical lists with separators. | ||
links: | ||
- label: GitHub | ||
icon: i-simple-icons-github | ||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/layout/List.vue | ||
--- | ||
|
||
## Usage | ||
|
||
Add items to the `UList` component, and a separator using the [`separator-before`](#separator-before) or [`separator-after`](#separator-after) slots. | ||
|
||
List items can be from simple HTML elements, to a `v-for` loop of components. | ||
|
||
:component-example{component="list-example"} | ||
|
||
::callout{icon="i-heroicons-light-bulb"} | ||
Lists are unordered by default, and are created using the `ul` tag. You can change the tag to `ol` for semantically ordered list by setting the `ordered` prop to `true`. This does not make any visual change. | ||
:: | ||
|
||
### Orientation | ||
|
||
By default, list items are stacked vertically. To stack the list items horizontally, set the `orientation` prop to `horizontal`. | ||
|
||
:component-example{component="list-example-orientation"} | ||
|
||
::callout{icon="i-heroicons-light-bulb"} | ||
You can also change the default orientation for all list through the [global UI config](#/getting-started/theming#appconfigts). | ||
:: | ||
|
||
### Item Orientation | ||
|
||
Both content and separators have the same stacking orientation than the list. For example, if a list is stacked vertically, the container holding the content and the separators will also be stacked vertically. | ||
|
||
The `itemOrientation` allows to change the stacking orientation of the item regardless of the list orientation. | ||
|
||
:component-example{component="list-example-item-orientation"} | ||
|
||
### Gap | ||
|
||
To add a default space in between each list item, set the `gap` prop. | ||
|
||
:component-example{component="list-example-gap"} | ||
|
||
Alternatively, you may set a custom gap using the `class` attribute like any other HTML Element. | ||
|
||
:component-example{component="list-example-padding-class"} | ||
|
||
::callout{icon="i-heroicons-light-bulb"} | ||
Items are listed using Tailwind CSS [`flex`](https://tailwindcss.com/docs/flex). You can change this through the [UI configuration](#config). | ||
:: | ||
|
||
### Wrapping | ||
|
||
When the items exceed the container height or width, these will not be wrapped into another line. To enable this behaviour, set the `wrap` prop. | ||
|
||
:component-example{component="list-example-wrap"} | ||
|
||
## Slots | ||
|
||
### `separator-before` | ||
|
||
Use this slot to set a separator **before** the item **contents**. It receives the current `index` of the item where is located, and both `isFirst` and `isLast` boolean if is the first or last item of the list, respectively. | ||
|
||
:component-example{component="list-example-slot-separator-before"} | ||
|
||
::callout{icon="i-heroicons-exclamation-triangle"} | ||
Both `isFirst` and `isLast` booleans always returns `true` if there is only one item. | ||
:: | ||
|
||
### `separator-after` | ||
|
||
Use this slot to set a separator **after** the item **contents**. It receives the current `index` of the item where is located, and both `isFirst` and `isLast` boolean if is the first or last item of the list, respectively. | ||
|
||
:component-example{component="list-example-slot-separator-after"} | ||
|
||
::callout{icon="i-heroicons-exclamation-triangle"} | ||
Both `isFirst` and `isLast` booleans always returns `true` if there is only one item. | ||
:: | ||
|
||
## Props | ||
|
||
:component-props | ||
|
||
## Config | ||
|
||
:component-preset |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { h, computed, toRef, defineComponent } from 'vue' | ||
import type { PropType, SlotsType } from 'vue' | ||
import type { RequireAtLeastOne } from 'type-fest' | ||
import { twMerge, twJoin } from 'tailwind-merge' | ||
import { useUI } from '../../composables/useUI' | ||
import type { Strategy } from '../../types' | ||
// @ts-expect-error | ||
import appConfig from '#build/app.config' | ||
import { mergeConfig, getSlotsChildren } from '#ui/utils' | ||
import { list } from '#ui/ui.config' | ||
|
||
const config = mergeConfig<typeof list>(appConfig.ui.strategy, appConfig.ui.list, list) | ||
|
||
export default defineComponent({ | ||
inheritAttrs: false, | ||
props: { | ||
ordered: { | ||
type: Boolean, | ||
default: false | ||
}, | ||
orientation: { | ||
type: String as PropType<'horizontal' | 'vertical'>, | ||
default: () => config.orientation, | ||
validator (value: string) { | ||
return ['horizontal', 'vertical'].includes(value) | ||
} | ||
}, | ||
gap: { | ||
type: Boolean, | ||
default: false | ||
}, | ||
wrap: { | ||
type: Boolean, | ||
default: () => config.wrapItems | ||
}, | ||
itemOrientation: { | ||
type: String as PropType<'horizontal' | 'vertical'>, | ||
default: undefined, | ||
validator (value: string|undefined) { | ||
return value === undefined ? true : ['horizontal', 'vertical'].includes(value) | ||
} | ||
}, | ||
class: { | ||
type: [String, Object, Array] as PropType<any>, | ||
default: undefined | ||
}, | ||
ui: { | ||
type: Object as PropType<Partial<typeof config & { strategy?: Strategy }>>, | ||
default: undefined | ||
} | ||
}, | ||
slots: Object as SlotsType< | ||
RequireAtLeastOne<{ | ||
default: undefined, | ||
'separator-before'?: { index: number, isFirst: boolean, isLast: boolean }, | ||
'separator-after'?: { index: number, isFirst: boolean, isLast: boolean }, | ||
}, 'separator-before' | 'separator-after'> | ||
>, | ||
setup (props, { slots }) { | ||
const { ui, attrs } = useUI('list', toRef(props, 'ui'), config) | ||
|
||
const listClass = computed(() => { | ||
return twMerge(twJoin( | ||
ui.value[props.orientation].base, | ||
props.wrap ? ui.value.wrap : ui.value.nowrap, | ||
props.gap ? ui.value[props.orientation].gap : '' | ||
), props.class) | ||
}) | ||
|
||
const itemClass = computed(() => { | ||
return twJoin( | ||
ui.value[props.itemOrientation ?? props.orientation].base, | ||
ui.value.nowrap | ||
) | ||
}) | ||
|
||
function addSeparator (array) { | ||
return array.map((item, index) => { | ||
const children = [] | ||
|
||
const isFirst = array.length === 1 | ||
|| ((slots['separator-before'] && index === 1) || (slots['separator-after'] && index === 0)) | ||
|
||
const isLast = array.length === 1 | ||
|| ((slots['separator-before'] && index === (array.length - 1)) || (slots['separator-after'] && index === (array.length - 2))) | ||
|
||
if (slots['separator-before'] && (index > 0)) { | ||
children.push(slots['separator-before']({ index, isFirst, isLast })) | ||
} | ||
|
||
children.push(item) | ||
|
||
if (slots['separator-after'] && (index < (array.length - 1))) { | ||
children.push(slots['separator-after']({ index, isFirst, isLast })) | ||
} | ||
|
||
return h('li', { class: itemClass.value }, children) | ||
}) | ||
} | ||
|
||
const children = computed(() => addSeparator(getSlotsChildren(slots))) | ||
|
||
const orderedElement = computed(() => props.ordered ? 'ol' : 'ul') | ||
|
||
return () => h(orderedElement.value, { ...attrs.value, class: listClass.value, ref: 'list' }, children.value) | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters