Skip to content

Commit b742c6e

Browse files
feat(Icon): allow passing a component instead of a name (#4766)
Co-authored-by: Benjamin Canac <[email protected]>
1 parent 1b2c2dd commit b742c6e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+237
-173
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script setup lang="ts">
2+
import { h } from 'vue'
3+
4+
const IconLightbulb = () => h(
5+
'svg',
6+
{ xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24' },
7+
[
8+
h(
9+
'path',
10+
{
11+
'fill': 'none',
12+
'stroke': 'currentColor',
13+
'stroke-linecap': 'round',
14+
'stroke-linejoin': 'round',
15+
'stroke-width': 2,
16+
'd': 'M15 14c.2-1 .7-1.7 1.5-2.5c1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5c.7.7 1.3 1.5 1.5 2.5m0 4h6m-5 4h4'
17+
}
18+
)
19+
]
20+
)
21+
</script>
22+
23+
<template>
24+
<UIcon :name="IconLightbulb" class="size-5" />
25+
</template>

docs/content/docs/2.components/icon.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
description: A component to display any icon from Iconify.
2+
description: A component to display any icon from Iconify or another component.
33
category: element
44
links:
55
- label: Icônes
@@ -27,6 +27,30 @@ It's highly recommended to install the icons collections you need, read more abo
2727
:::
2828
::
2929

30+
## Examples
31+
32+
### SVG
33+
34+
You can also pass a Vue component into the `name` prop:
35+
36+
::component-example
37+
---
38+
name: 'icon-svg-example'
39+
---
40+
::
41+
42+
You can define your icon components yourself, or use [`unplugin-icons`](https://github.com/unplugin/unplugin-icons) to import them directly from SVG files:
43+
44+
```vue
45+
<script setup lang="ts">
46+
import IconLightbulb from '~icons/lucide/lightbulb'
47+
</script>
48+
49+
<template>
50+
<UIcon :name="IconLightbulb" class="size-5" />
51+
</template>
52+
```
53+
3054
## API
3155

3256
### Props

src/runtime/components/Accordion.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import type { AccordionRootProps, AccordionRootEmits } from 'reka-ui'
44
import type { AppConfig } from '@nuxt/schema'
55
import theme from '#build/ui/accordion'
6+
import type { IconProps } from '../types'
67
import type { DynamicSlots } from '../types/utils'
78
import type { ComponentConfig } from '../types/tv'
89
@@ -13,11 +14,11 @@ export interface AccordionItem {
1314
/**
1415
* @IconifyIcon
1516
*/
16-
icon?: string
17+
icon?: IconProps['name']
1718
/**
1819
* @IconifyIcon
1920
*/
20-
trailingIcon?: string
21+
trailingIcon?: IconProps['name']
2122
slot?: string
2223
content?: string
2324
/** A unique value for the accordion item. Defaults to the index. */
@@ -40,7 +41,7 @@ export interface AccordionProps<T extends AccordionItem = AccordionItem> extends
4041
* @defaultValue appConfig.ui.icons.chevronDown
4142
* @IconifyIcon
4243
*/
43-
trailingIcon?: string
44+
trailingIcon?: IconProps['name']
4445
/**
4546
* The key used to get the label from the item.
4647
* @defaultValue 'label'

src/runtime/components/Alert.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
import type { AppConfig } from '@nuxt/schema'
33
import theme from '#build/ui/alert'
4-
import type { AvatarProps, ButtonProps } from '../types'
4+
import type { AvatarProps, ButtonProps, IconProps } from '../types'
55
import type { ComponentConfig } from '../types/tv'
66
77
type Alert = ComponentConfig<typeof theme, AppConfig, 'alert'>
@@ -17,7 +17,7 @@ export interface AlertProps {
1717
/**
1818
* @IconifyIcon
1919
*/
20-
icon?: string
20+
icon?: IconProps['name']
2121
avatar?: AvatarProps
2222
/**
2323
* @defaultValue 'primary'
@@ -51,7 +51,7 @@ export interface AlertProps {
5151
* @defaultValue appConfig.ui.icons.close
5252
* @IconifyIcon
5353
*/
54-
closeIcon?: string
54+
closeIcon?: IconProps['name']
5555
class?: any
5656
ui?: Alert['slots']
5757
}

src/runtime/components/AuthForm.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<script lang="ts">
33
import type { AppConfig } from '@nuxt/schema'
44
import theme from '#build/ui/auth-form'
5-
import type { ButtonProps, FormProps, FormFieldProps, SeparatorProps, PinInputProps } from '../types'
5+
import type { ButtonProps, FormProps, FormFieldProps, SeparatorProps, PinInputProps, IconProps } from '../types'
66
import type { FormSchema, FormSubmitEvent, InferInput } from '../types/form'
77
import type { ComponentConfig } from '../types/tv'
88
@@ -29,7 +29,7 @@ export interface AuthFormProps<T extends FormSchema = FormSchema<object>, F exte
2929
* The icon displayed above the title.
3030
* @IconifyIcon
3131
*/
32-
icon?: string
32+
icon?: IconProps['name']
3333
title?: string
3434
description?: string
3535
fields?: F[]

src/runtime/components/Avatar.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
import type { AppConfig } from '@nuxt/schema'
33
import theme from '#build/ui/avatar'
4-
import type { ChipProps } from '../types'
4+
import type { ChipProps, IconProps } from '../types'
55
import type { ComponentConfig } from '../types/tv'
66
77
type Avatar = ComponentConfig<typeof theme, AppConfig, 'avatar'>
@@ -17,7 +17,7 @@ export interface AvatarProps {
1717
/**
1818
* @IconifyIcon
1919
*/
20-
icon?: string
20+
icon?: IconProps['name']
2121
text?: string
2222
/**
2323
* @defaultValue 'md'

src/runtime/components/Banner.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
import type { AppConfig } from '@nuxt/schema'
33
import theme from '#build/ui/banner'
4-
import type { ButtonProps, LinkProps } from '../types'
4+
import type { ButtonProps, IconProps, LinkProps } from '../types'
55
import type { ComponentConfig } from '../types/tv'
66
77
type Banner = ComponentConfig<typeof theme, AppConfig, 'banner'>
@@ -22,7 +22,7 @@ export interface BannerProps {
2222
* The icon displayed next to the title.
2323
* @IconifyIcon
2424
*/
25-
icon?: string
25+
icon?: IconProps['name']
2626
title?: string
2727
/**
2828
* Display a list of actions next to the title.
@@ -47,7 +47,7 @@ export interface BannerProps {
4747
* @defaultValue appConfig.ui.icons.close
4848
* @IconifyIcon
4949
*/
50-
closeIcon?: string
50+
closeIcon?: IconProps['name']
5151
class?: any
5252
ui?: Banner['slots']
5353
}

src/runtime/components/Breadcrumb.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<script lang="ts">
33
import type { AppConfig } from '@nuxt/schema'
44
import theme from '#build/ui/breadcrumb'
5-
import type { AvatarProps, LinkProps } from '../types'
5+
import type { AvatarProps, IconProps, LinkProps } from '../types'
66
import type { DynamicSlots } from '../types/utils'
77
import type { ComponentConfig } from '../types/tv'
88
@@ -13,7 +13,7 @@ export interface BreadcrumbItem extends Omit<LinkProps, 'raw' | 'custom'> {
1313
/**
1414
* @IconifyIcon
1515
*/
16-
icon?: string
16+
icon?: IconProps['name']
1717
avatar?: AvatarProps
1818
slot?: string
1919
class?: any
@@ -33,7 +33,7 @@ export interface BreadcrumbProps<T extends BreadcrumbItem = BreadcrumbItem> {
3333
* @defaultValue appConfig.ui.icons.chevronRight
3434
* @IconifyIcon
3535
*/
36-
separatorIcon?: string
36+
separatorIcon?: IconProps['name']
3737
/**
3838
* The key used to get the label from the item.
3939
* @defaultValue 'label'

src/runtime/components/Calendar.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { CalendarRootProps, CalendarRootEmits, RangeCalendarRootProps, Rang
33
import type { DateValue } from '@internationalized/date'
44
import type { AppConfig } from '@nuxt/schema'
55
import theme from '#build/ui/calendar'
6-
import type { ButtonProps } from '../types'
6+
import type { ButtonProps, IconProps } from '../types'
77
import type { ComponentConfig } from '../types/tv'
88
99
type Calendar = ComponentConfig<typeof theme, AppConfig, 'calendar'>
@@ -33,7 +33,7 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
3333
* @defaultValue appConfig.ui.icons.chevronDoubleRight
3434
* @IconifyIcon
3535
*/
36-
nextYearIcon?: string
36+
nextYearIcon?: IconProps['name']
3737
/**
3838
* Configure the next year button.
3939
* `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
@@ -44,7 +44,7 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
4444
* @defaultValue appConfig.ui.icons.chevronRight
4545
* @IconifyIcon
4646
*/
47-
nextMonthIcon?: string
47+
nextMonthIcon?: IconProps['name']
4848
/**
4949
* Configure the next month button.
5050
* `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
@@ -55,7 +55,7 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
5555
* @defaultValue appConfig.ui.icons.chevronDoubleLeft
5656
* @IconifyIcon
5757
*/
58-
prevYearIcon?: string
58+
prevYearIcon?: IconProps['name']
5959
/**
6060
* Configure the prev year button.
6161
* `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
@@ -66,7 +66,7 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
6666
* @defaultValue appConfig.ui.icons.chevronLeft
6767
* @IconifyIcon
6868
*/
69-
prevMonthIcon?: string
69+
prevMonthIcon?: IconProps['name']
7070
/**
7171
* Configure the prev month button.
7272
* `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}

src/runtime/components/Carousel.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { ClassNamesOptionsType } from 'embla-carousel-class-names'
1010
import type { FadeOptionsType } from 'embla-carousel-fade'
1111
import type { WheelGesturesPluginOptions } from 'embla-carousel-wheel-gestures'
1212
import theme from '#build/ui/carousel'
13-
import type { ButtonProps } from '../types'
13+
import type { ButtonProps, IconProps } from '../types'
1414
import type { ComponentConfig } from '../types/tv'
1515
1616
type Carousel = ComponentConfig<typeof theme, AppConfig, 'carousel'>
@@ -39,7 +39,7 @@ export interface CarouselProps<T extends CarouselItem = CarouselItem> extends Om
3939
* @defaultValue appConfig.ui.icons.arrowLeft
4040
* @IconifyIcon
4141
*/
42-
prevIcon?: string
42+
prevIcon?: IconProps['name']
4343
/**
4444
* Configure the next button when arrows are enabled.
4545
* @defaultValue { size: 'md', color: 'neutral', variant: 'link' }
@@ -50,7 +50,7 @@ export interface CarouselProps<T extends CarouselItem = CarouselItem> extends Om
5050
* @defaultValue appConfig.ui.icons.arrowRight
5151
* @IconifyIcon
5252
*/
53-
nextIcon?: string
53+
nextIcon?: IconProps['name']
5454
/**
5555
* Display prev and next buttons to scroll the carousel.
5656
* @defaultValue false

0 commit comments

Comments
 (0)