mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-18 05:58:07 +01:00
fix(components): ui prop override with class (#136)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
const useContentExamplesCodeState = () => useState('content-examples-code', () => ({}))
|
||||
|
||||
export async function fetchContentExampleCode (name?: string) {
|
||||
export async function fetchContentExampleCode(name?: string) {
|
||||
if (!name) return
|
||||
const state = useContentExamplesCodeState()
|
||||
|
||||
@@ -8,7 +8,9 @@ export async function fetchContentExampleCode (name?: string) {
|
||||
await state.value[name]
|
||||
return state.value[name]
|
||||
}
|
||||
if (state.value[name]) { return state.value[name] }
|
||||
if (state.value[name]) {
|
||||
return state.value[name]
|
||||
}
|
||||
|
||||
// add to nitro prerender
|
||||
if (import.meta.server) {
|
||||
@@ -1,31 +0,0 @@
|
||||
import { createShikiHighlighter } from '@nuxtjs/mdc/runtime/highlighter/shiki'
|
||||
import MaterialTheme from 'shiki/themes/material-theme.mjs'
|
||||
import MaterialThemeLighter from 'shiki/themes/material-theme-lighter.mjs'
|
||||
import MaterialThemePalenight from 'shiki/themes/material-theme-palenight.mjs'
|
||||
import HtmlLang from 'shiki/langs/html.mjs'
|
||||
import MdcLang from 'shiki/langs/mdc.mjs'
|
||||
import VueLang from 'shiki/langs/vue.mjs'
|
||||
import YamlLang from 'shiki/langs/yaml.mjs'
|
||||
import PostcssLang from 'shiki/langs/postcss.mjs'
|
||||
|
||||
let highlighter
|
||||
export const useShikiHighlighter = () => {
|
||||
if (!highlighter) {
|
||||
highlighter = createShikiHighlighter({
|
||||
bundledThemes: {
|
||||
'material-theme': MaterialTheme,
|
||||
'material-theme-lighter': MaterialThemeLighter,
|
||||
'material-theme-palenight': MaterialThemePalenight
|
||||
},
|
||||
bundledLangs: {
|
||||
html: HtmlLang,
|
||||
mdc: MdcLang,
|
||||
vue: VueLang,
|
||||
yml: YamlLang,
|
||||
postcss: PostcssLang
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return highlighter
|
||||
}
|
||||
@@ -2,10 +2,10 @@ import type { Options } from 'prettier'
|
||||
import PrettierWorker from '@/workers/prettier.js?worker&inline'
|
||||
|
||||
export interface SimplePrettier {
|
||||
format: (source: string, options?: Options) => Promise<string>;
|
||||
format: (source: string, options?: Options) => Promise<string>
|
||||
}
|
||||
|
||||
function createPrettierWorkerApi (worker: Worker): SimplePrettier {
|
||||
function createPrettierWorkerApi(worker: Worker): SimplePrettier {
|
||||
let counter = 0
|
||||
const handlers = {}
|
||||
|
||||
@@ -17,6 +17,7 @@ function createPrettierWorkerApi (worker: Worker): SimplePrettier {
|
||||
}
|
||||
|
||||
const [resolve, reject] = handlers[uid]
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete handlers[uid]
|
||||
|
||||
if (error) {
|
||||
@@ -26,7 +27,7 @@ function createPrettierWorkerApi (worker: Worker): SimplePrettier {
|
||||
}
|
||||
})
|
||||
|
||||
function postMessage<T> (message) {
|
||||
function postMessage<T>(message) {
|
||||
const uid = ++counter
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
handlers[uid] = [resolve, reject]
|
||||
@@ -35,19 +36,19 @@ function createPrettierWorkerApi (worker: Worker): SimplePrettier {
|
||||
}
|
||||
|
||||
return {
|
||||
format (source: string, options?: Options) {
|
||||
format(source: string, options?: Options) {
|
||||
return postMessage({ type: 'format', source, options })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default defineNuxtPlugin({
|
||||
async setup () {
|
||||
async setup() {
|
||||
let prettier: SimplePrettier
|
||||
if (import.meta.server) {
|
||||
const prettierModule = await import('prettier')
|
||||
prettier = {
|
||||
format (source, options = {
|
||||
format(source, options = {
|
||||
parser: 'markdown'
|
||||
}) {
|
||||
return prettierModule.format(source, options)
|
||||
|
||||
@@ -10,14 +10,14 @@ self.onmessage = async function (event) {
|
||||
})
|
||||
}
|
||||
|
||||
function handleMessage (message) {
|
||||
function handleMessage(message) {
|
||||
switch (message.type) {
|
||||
case 'format':
|
||||
return handleFormatMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleFormatMessage (message) {
|
||||
async function handleFormatMessage(message) {
|
||||
const { options, source } = message
|
||||
const formatted = await prettier.format(source, {
|
||||
parser: 'markdown',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { existsSync, readFileSync } from 'fs'
|
||||
import fsp from 'fs/promises'
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import fsp from 'node:fs/promises'
|
||||
import { dirname, join } from 'pathe'
|
||||
import { defineNuxtModule, addTemplate, addServerHandler, createResolver } from '@nuxt/kit'
|
||||
|
||||
@@ -7,20 +7,20 @@ export default defineNuxtModule({
|
||||
meta: {
|
||||
name: 'content-examples-code'
|
||||
},
|
||||
async setup (_options, nuxt) {
|
||||
async setup(_options, nuxt) {
|
||||
const resolver = createResolver(import.meta.url)
|
||||
let _configResolved: any
|
||||
let components: Record<string, any>
|
||||
const outputPath = join(nuxt.options.buildDir, 'content-examples-code')
|
||||
|
||||
async function stubOutput () {
|
||||
async function stubOutput() {
|
||||
if (existsSync(outputPath + '.mjs')) {
|
||||
return
|
||||
}
|
||||
await updateOutput('export default {}')
|
||||
}
|
||||
|
||||
async function fetchComponent (component: string | any) {
|
||||
async function fetchComponent(component: string | any) {
|
||||
if (typeof component === 'string') {
|
||||
if (components[component]) {
|
||||
component = components[component]
|
||||
@@ -51,7 +51,7 @@ export default defineNuxtModule({
|
||||
const getVirtualModuleContent = () =>
|
||||
`export default ${getStringifiedComponents()}`
|
||||
|
||||
async function updateOutput (content?: string) {
|
||||
async function updateOutput(content?: string) {
|
||||
const path = outputPath + '.mjs'
|
||||
if (!existsSync(dirname(path))) {
|
||||
await fsp.mkdir(dirname(path), { recursive: true })
|
||||
@@ -62,13 +62,13 @@ export default defineNuxtModule({
|
||||
await fsp.writeFile(path, content || getVirtualModuleContent(), 'utf-8')
|
||||
}
|
||||
|
||||
async function fetchComponents () {
|
||||
async function fetchComponents() {
|
||||
await Promise.all(Object.keys(components).map(fetchComponent))
|
||||
}
|
||||
|
||||
nuxt.hook('components:extend', async (_components) => {
|
||||
components = _components
|
||||
.filter((v) => v.shortPath.includes('components/content/examples/'))
|
||||
.filter(v => v.shortPath.includes('components/content/examples/'))
|
||||
.reduce((acc, component) => {
|
||||
acc[component.pascalName] = component
|
||||
return acc
|
||||
@@ -87,17 +87,17 @@ export default defineNuxtModule({
|
||||
vite.config.plugins.push({
|
||||
name: 'content-examples-code',
|
||||
enforce: 'post',
|
||||
async buildStart () {
|
||||
async buildStart() {
|
||||
if (_configResolved?.build.ssr) {
|
||||
return
|
||||
}
|
||||
await fetchComponents()
|
||||
await updateOutput()
|
||||
},
|
||||
configResolved (config) {
|
||||
configResolved(config) {
|
||||
_configResolved = config
|
||||
},
|
||||
async handleHotUpdate ({ file }) {
|
||||
async handleHotUpdate({ file }) {
|
||||
if (
|
||||
Object.entries(components).some(
|
||||
([, comp]: any) => comp.filePath === file
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineEventHandler, createError, appendHeader } from 'h3'
|
||||
import { pascalCase } from 'scule'
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error - no types available
|
||||
import components from '#content-examples-code/nitro'
|
||||
|
||||
export default defineEventHandler((event) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Octokit } from '@octokit/rest'
|
||||
|
||||
function isUserABot (user) {
|
||||
function isUserABot(user) {
|
||||
return user?.login?.endsWith('-bot') || user?.login?.endsWith('[bot]')
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,9 @@ const appConfig = useAppConfig()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'collapsible', 'defaultValue', 'disabled', 'modelValue', 'type'), emits)
|
||||
const contentProps = toRef(() => props.content)
|
||||
|
||||
const ui = computed(() => tv({ extend: accordion, slots: props.ui })({ disabled: props.disabled }))
|
||||
const ui = computed(() => accordion({
|
||||
disabled: props.disabled
|
||||
}))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -76,25 +78,25 @@ const ui = computed(() => tv({ extend: accordion, slots: props.ui })({ disabled:
|
||||
:key="index"
|
||||
:value="item.value || String(index)"
|
||||
:disabled="item.disabled"
|
||||
:class="ui.item()"
|
||||
:class="ui.item({ class: props.ui?.item })"
|
||||
>
|
||||
<AccordionHeader :class="ui.header()">
|
||||
<AccordionTrigger :class="ui.trigger({ disabled: item.disabled })">
|
||||
<AccordionHeader :class="ui.header({ class: props.ui?.header })">
|
||||
<AccordionTrigger :class="ui.trigger({ class: props.ui?.trigger, disabled: item.disabled })">
|
||||
<slot name="leading" :item="item" :index="index" :open="open">
|
||||
<UIcon v-if="item.icon" :name="item.icon" :class="ui.leadingIcon()" />
|
||||
<UIcon v-if="item.icon" :name="item.icon" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
</slot>
|
||||
|
||||
<span v-if="item.label || !!slots.default" :class="ui.label()">
|
||||
<span v-if="item.label || !!slots.default" :class="ui.label({ class: props.ui?.label })">
|
||||
<slot :item="item" :index="index" :open="open">{{ item.label }}</slot>
|
||||
</span>
|
||||
|
||||
<slot name="trailing" :item="item" :index="index" :open="open">
|
||||
<UIcon :name="item.trailingIcon || trailingIcon || appConfig.ui.icons.chevronDown" :class="ui.trailingIcon()" />
|
||||
<UIcon :name="item.trailingIcon || trailingIcon || appConfig.ui.icons.chevronDown" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
|
||||
</slot>
|
||||
</AccordionTrigger>
|
||||
</AccordionHeader>
|
||||
|
||||
<AccordionContent v-if="item.content || !!slots.content || (item.slot && !!slots[item.slot])" v-bind="contentProps" :class="ui.content()">
|
||||
<AccordionContent v-if="item.content || !!slots.content || (item.slot && !!slots[item.slot])" v-bind="contentProps" :class="ui.content({ class: props.ui?.content })">
|
||||
<slot :name="item.slot || 'content'" :item="item" :index="index" :open="open">
|
||||
{{ item.content }}
|
||||
</slot>
|
||||
|
||||
@@ -54,7 +54,7 @@ export interface AlertSlots {
|
||||
title(props?: {}): any
|
||||
description(props?: {}): any
|
||||
actions(props?: {}): any
|
||||
close(props: { class: string }): any
|
||||
close(props: { ui: any }): any
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -72,7 +72,7 @@ const appConfig = useAppConfig()
|
||||
|
||||
const multiline = computed(() => !!props.title && !!props.description)
|
||||
|
||||
const ui = computed(() => tv({ extend: alert, slots: props.ui })({
|
||||
const ui = computed(() => alert({
|
||||
color: props.color,
|
||||
variant: props.variant
|
||||
}))
|
||||
@@ -81,39 +81,39 @@ const ui = computed(() => tv({ extend: alert, slots: props.ui })({
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: props.class, multiline })">
|
||||
<slot name="leading">
|
||||
<UAvatar v-if="avatar" size="2xl" v-bind="avatar" :class="ui.avatar()" />
|
||||
<UIcon v-else-if="icon" :name="icon" :class="ui.icon()" />
|
||||
<UAvatar v-if="avatar" size="2xl" v-bind="avatar" :class="ui.avatar({ class: props.ui?.avatar })" />
|
||||
<UIcon v-else-if="icon" :name="icon" :class="ui.icon({ class: props.ui?.icon })" />
|
||||
</slot>
|
||||
|
||||
<div :class="ui.wrapper()">
|
||||
<div v-if="title || !!slots.title" :class="ui.title()">
|
||||
<div :class="ui.wrapper({ class: props.ui?.wrapper })">
|
||||
<div v-if="title || !!slots.title" :class="ui.title({ class: props.ui?.title })">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</div>
|
||||
<template v-if="description || !!slots.description">
|
||||
<div :class="ui.description()">
|
||||
<div :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="multiline && actions?.length" :class="ui.actions({ multiline: true })">
|
||||
<div v-if="multiline && actions?.length" :class="ui.actions({ class: props.ui?.actions, multiline: true })">
|
||||
<slot name="actions">
|
||||
<UButton v-for="(action, index) in actions" :key="index" size="xs" v-bind="action" />
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="(!multiline && actions?.length) || close" :class="ui.actions({ multiline: false })">
|
||||
<div v-if="(!multiline && actions?.length) || close" :class="ui.actions({ class: props.ui?.actions, multiline: false })">
|
||||
<template v-if="!multiline">
|
||||
<slot name="actions">
|
||||
<UButton v-for="(action, index) in actions" :key="index" size="xs" v-bind="action" />
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<slot name="close" :class="ui.close()">
|
||||
<slot name="close" :ui="ui">
|
||||
<UButton
|
||||
v-if="close"
|
||||
:icon="closeIcon || appConfig.ui.icons.close"
|
||||
@@ -122,7 +122,7 @@ const ui = computed(() => tv({ extend: alert, slots: props.ui })({
|
||||
variant="link"
|
||||
aria-label="Close"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close()"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
@click="emits('close')"
|
||||
/>
|
||||
</slot>
|
||||
|
||||
@@ -38,16 +38,19 @@ const fallback = computed(() => props.text || (props.alt || '').split(' ').map(w
|
||||
|
||||
const { size } = useAvatarGroup(props)
|
||||
|
||||
const ui = computed(() => tv({ extend: avatar, slots: props.ui })({ size: size.value }))
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = computed(() => avatar({
|
||||
size: size.value
|
||||
}))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AvatarRoot :class="ui.root({ class: props.class })">
|
||||
<AvatarImage v-if="src" :as="as" :src="src" :alt="alt" :class="ui.image()" />
|
||||
<AvatarImage v-if="src" :as="as" :src="src" :alt="alt" :class="ui.image({ class: props.ui?.image })" />
|
||||
|
||||
<AvatarFallback as-child v-bind="fallbackProps">
|
||||
<UIcon v-if="icon" :name="icon" :class="ui.icon()" />
|
||||
<span v-else :class="ui.fallback()">{{ fallback }}</span>
|
||||
<UIcon v-if="icon" :name="icon" :class="ui.icon({ class: props.ui?.icon })" />
|
||||
<span v-else :class="ui.fallback({ class: props.ui?.fallback })">{{ fallback }}</span>
|
||||
</AvatarFallback>
|
||||
</AvatarRoot>
|
||||
</template>
|
||||
|
||||
@@ -39,7 +39,7 @@ import { avatarGroupInjectionKey } from '#imports'
|
||||
const props = defineProps<AvatarGroupProps>()
|
||||
const slots = defineSlots<AvatarGroupSlots>()
|
||||
|
||||
const ui = computed(() => tv({ extend: avatarGroup, slots: props.ui })({
|
||||
const ui = computed(() => avatarGroup({
|
||||
size: props.size
|
||||
}))
|
||||
|
||||
@@ -74,7 +74,7 @@ provide(avatarGroupInjectionKey, computed(() => ({
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: props.class })">
|
||||
<UAvatar v-if="hiddenCount > 0" :text="`+${hiddenCount}`" :class="ui.base()" />
|
||||
<component :is="avatar" v-for="(avatar, count) in visibleAvatars" :key="count" :class="ui.base()" />
|
||||
<UAvatar v-if="hiddenCount > 0" :text="`+${hiddenCount}`" :class="ui.base({ class: props.ui?.base })" />
|
||||
<component :is="avatar" v-for="(avatar, count) in visibleAvatars" :key="count" :class="ui.base({ class: props.ui?.base })" />
|
||||
</Primitive>
|
||||
</template>
|
||||
|
||||
@@ -45,7 +45,6 @@ export type BreadcrumbSlots<T extends { slot?: string }> = {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends BreadcrumbItem">
|
||||
import { computed } from 'vue'
|
||||
import { Primitive } from 'radix-vue'
|
||||
import { useAppConfig } from '#imports'
|
||||
import { ULink, UIcon, UAvatar } from '#components'
|
||||
@@ -56,23 +55,24 @@ const slots = defineSlots<BreadcrumbSlots<T>>()
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed(() => tv({ extend: breadcrumb, slots: props.ui })())
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = breadcrumb()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" aria-label="breadcrumb" :class="ui.root({ class: props.class })">
|
||||
<ol :class="ui.list()">
|
||||
<ol :class="ui.list({ class: props.ui?.list })">
|
||||
<template v-for="(item, index) in items" :key="index">
|
||||
<li :class="ui.item()">
|
||||
<li :class="ui.item({ class: props.ui?.item })">
|
||||
<ULink v-slot="{ active, ...slotProps }" v-bind="pickLinkProps(item)" custom>
|
||||
<ULinkBase v-bind="slotProps" as="span" :aria-current="active && (index === items!.length - 1) ? 'page' : undefined" :class="ui.link({ active: index === items!.length - 1, disabled: !!item.disabled, to: !!item.to })">
|
||||
<ULinkBase v-bind="slotProps" as="span" :aria-current="active && (index === items!.length - 1) ? 'page' : undefined" :class="ui.link({ class: props.ui?.link, active: index === items!.length - 1, disabled: !!item.disabled, to: !!item.to })">
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<slot :name="item.slot ? `${item.slot}-leading`: 'item-leading'" :item="item" :active="index === items!.length - 1" :index="index">
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ active: index === items!.length - 1 })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ active: index === items!.length - 1 })" />
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ class: props.ui?.linkLeadingAvatar, active: index === items!.length - 1 })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ class: props.ui?.linkLeadingIcon, active: index === items!.length - 1 })" />
|
||||
</slot>
|
||||
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label`: 'item-label']" :class="ui.linkLabel()">
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label`: 'item-label']" :class="ui.linkLabel({ class: props.ui?.linkLabel })">
|
||||
<slot :name="item.slot ? `${item.slot}-label`: 'item-label'" :item="item" :active="index === items!.length - 1" :index="index">
|
||||
{{ item.label }}
|
||||
</slot>
|
||||
@@ -84,9 +84,9 @@ const ui = computed(() => tv({ extend: breadcrumb, slots: props.ui })())
|
||||
</ULink>
|
||||
</li>
|
||||
|
||||
<li v-if="index < items!.length - 1" role="presentation" :class="ui.separator()">
|
||||
<li v-if="index < items!.length - 1" role="presentation" :class="ui.separator({ class: props.ui?.separator })">
|
||||
<slot name="separator">
|
||||
<UIcon :name="separatorIcon || appConfig.ui.icons.chevronRight" :class="ui.separatorIcon()" />
|
||||
<UIcon :name="separatorIcon || appConfig.ui.icons.chevronRight" :class="ui.separatorIcon({ class: props.ui?.separatorIcon })" />
|
||||
</slot>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
@@ -48,7 +48,7 @@ const linkProps = useForwardProps(pickLinkProps(props))
|
||||
const { orientation, size: buttonSize } = useButtonGroup<ButtonProps>(props)
|
||||
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props)
|
||||
|
||||
const ui = computed(() => tv({ extend: button, slots: props.ui })({
|
||||
const ui = computed(() => button({
|
||||
color: props.color,
|
||||
variant: props.variant,
|
||||
size: buttonSize.value,
|
||||
@@ -64,17 +64,17 @@ const ui = computed(() => tv({ extend: button, slots: props.ui })({
|
||||
<template>
|
||||
<ULink :type="type" :disabled="disabled || loading" :class="ui.base({ class: props.class })" v-bind="linkProps" raw>
|
||||
<slot name="leading">
|
||||
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon()" />
|
||||
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
</slot>
|
||||
|
||||
<span v-if="label || !!slots.default" :class="ui.label()">
|
||||
<span v-if="label || !!slots.default" :class="ui.label({ class: props.ui?.label })">
|
||||
<slot>
|
||||
{{ label }}
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<slot name="trailing">
|
||||
<UIcon v-if="isTrailing && trailingIconName" :name="trailingIconName" :class="ui.trailingIcon()" />
|
||||
<UIcon v-if="isTrailing && trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
|
||||
</slot>
|
||||
</ULink>
|
||||
</template>
|
||||
|
||||
@@ -26,26 +26,26 @@ export interface CardSlots {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { Primitive } from 'radix-vue'
|
||||
|
||||
const props = defineProps<CardProps>()
|
||||
const slots = defineSlots<CardSlots>()
|
||||
|
||||
const ui = computed(() => tv({ extend: card, slots: props.ui })())
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = card()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: props.class })">
|
||||
<div v-if="!!slots.header" :class="ui.header()">
|
||||
<div v-if="!!slots.header" :class="ui.header({ class: props.ui?.header })">
|
||||
<slot name="header" />
|
||||
</div>
|
||||
|
||||
<div v-if="!!slots.default" :class="ui.body()">
|
||||
<div v-if="!!slots.default" :class="ui.body({ class: props.ui?.body })">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<div v-if="!!slots.footer" :class="ui.footer()">
|
||||
<div v-if="!!slots.footer" :class="ui.footer({ class: props.ui?.footer })">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</Primitive>
|
||||
|
||||
@@ -74,7 +74,7 @@ const checked = computed({
|
||||
}
|
||||
})
|
||||
|
||||
const ui = computed(() => tv({ extend: checkbox, slots: props.ui })({
|
||||
const ui = computed(() => checkbox({
|
||||
size: size.value,
|
||||
color: color.value,
|
||||
required: props.required,
|
||||
@@ -93,7 +93,7 @@ function onUpdate(value: any) {
|
||||
|
||||
<template>
|
||||
<div :class="ui.root({ class: props.class })">
|
||||
<div :class="ui.container()">
|
||||
<div :class="ui.container({ class: props.ui?.container })">
|
||||
<CheckboxRoot
|
||||
:id="id"
|
||||
v-model:checked="checked"
|
||||
@@ -101,23 +101,23 @@ function onUpdate(value: any) {
|
||||
v-bind="rootProps"
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:class="ui.base()"
|
||||
:class="ui.base({ class: props.ui?.base })"
|
||||
@update:checked="onUpdate"
|
||||
>
|
||||
<CheckboxIndicator as-child>
|
||||
<UIcon v-if="indeterminate" :name="indeterminateIcon || appConfig.ui.icons.minus" :class="ui.icon()" />
|
||||
<UIcon v-else :name="icon || appConfig.ui.icons.check" :class="ui.icon()" />
|
||||
<UIcon v-if="indeterminate" :name="indeterminateIcon || appConfig.ui.icons.minus" :class="ui.icon({ class: props.ui?.icon })" />
|
||||
<UIcon v-else :name="icon || appConfig.ui.icons.check" :class="ui.icon({ class: props.ui?.icon })" />
|
||||
</CheckboxIndicator>
|
||||
</CheckboxRoot>
|
||||
</div>
|
||||
|
||||
<div v-if="(label || !!slots.label) || (description || !!slots.description)" :class="ui.wrapper()">
|
||||
<Label v-if="label || !!slots.label" :for="id" :class="ui.label()">
|
||||
<div v-if="(label || !!slots.label) || (description || !!slots.description)" :class="ui.wrapper({ class: props.ui?.wrapper })">
|
||||
<Label v-if="label || !!slots.label" :for="id" :class="ui.label({ class: props.ui?.label })">
|
||||
<slot name="label" :label="label">
|
||||
{{ label }}
|
||||
</slot>
|
||||
</Label>
|
||||
<p v-if="description || !!slots.description" :class="ui.description()">
|
||||
<p v-if="description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description" :description="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
|
||||
@@ -51,7 +51,7 @@ const show = defineModel<boolean>('show', { default: true })
|
||||
|
||||
const { size } = useAvatarGroup(props)
|
||||
|
||||
const ui = computed(() => tv({ extend: chip, slots: props.ui })({
|
||||
const ui = computed(() => chip({
|
||||
color: props.color,
|
||||
size: size.value,
|
||||
position: props.position,
|
||||
@@ -64,7 +64,7 @@ const ui = computed(() => tv({ extend: chip, slots: props.ui })({
|
||||
<Primitive :as="as" :class="ui.root({ class: props.class })">
|
||||
<slot />
|
||||
|
||||
<span v-if="show" :class="ui.base()">
|
||||
<span v-if="show" :class="ui.base({ class: props.ui?.base })">
|
||||
<slot name="content">
|
||||
{{ text }}
|
||||
</slot>
|
||||
|
||||
@@ -28,7 +28,6 @@ export interface CollapsibleSlots {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { CollapsibleRoot, CollapsibleTrigger, CollapsibleContent, useForwardPropsEmits } from 'radix-vue'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
|
||||
@@ -38,7 +37,8 @@ const slots = defineSlots<CollapsibleSlots>()
|
||||
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultOpen', 'open', 'disabled'), emits)
|
||||
|
||||
const ui = computed(() => tv({ extend: collapsible, slots: props.ui })())
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = collapsible()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -47,7 +47,7 @@ const ui = computed(() => tv({ extend: collapsible, slots: props.ui })())
|
||||
<slot :open="open" />
|
||||
</CollapsibleTrigger>
|
||||
|
||||
<CollapsibleContent :class="ui.content()">
|
||||
<CollapsibleContent :class="ui.content({ class: props.ui?.content })">
|
||||
<slot name="content" />
|
||||
</CollapsibleContent>
|
||||
</CollapsibleRoot>
|
||||
|
||||
@@ -84,7 +84,7 @@ type SlotProps<T> = (props: { item: T, index: number }) => any
|
||||
|
||||
export type CommandPaletteSlots<G extends { slot?: string }, T extends { slot?: string }> = {
|
||||
'empty'(props: { searchTerm?: string }): any
|
||||
'close'(props?: {}): any
|
||||
'close'(props: { ui: any }): any
|
||||
'item': SlotProps<T>
|
||||
'item-leading': SlotProps<T>
|
||||
'item-label': SlotProps<T>
|
||||
@@ -116,7 +116,8 @@ const appConfig = useAppConfig()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'disabled', 'multiple', 'modelValue', 'defaultValue'), emits)
|
||||
const inputProps = useForwardProps(reactivePick(props, 'loading', 'loadingIcon', 'placeholder'))
|
||||
|
||||
const ui = computed(() => tv({ extend: commandPalette, slots: props.ui })())
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = commandPalette()
|
||||
|
||||
const fuse = computed(() => defu({}, props.fuse, {
|
||||
fuseOptions: {
|
||||
@@ -187,10 +188,10 @@ const groups = computed(() => {
|
||||
size="lg"
|
||||
v-bind="inputProps"
|
||||
:icon="icon || appConfig.ui.icons.search"
|
||||
:class="ui.input()"
|
||||
:class="ui.input({ class: props.ui?.input })"
|
||||
>
|
||||
<template v-if="close || !!slots.close" #trailing>
|
||||
<slot name="close" :class="ui.close()">
|
||||
<slot name="close" :ui="ui">
|
||||
<UButton
|
||||
v-if="close"
|
||||
:icon="closeIcon || appConfig.ui.icons.close"
|
||||
@@ -199,7 +200,7 @@ const groups = computed(() => {
|
||||
variant="ghost"
|
||||
aria-label="Close"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close()"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
@click="emits('update:open', false)"
|
||||
/>
|
||||
</slot>
|
||||
@@ -208,16 +209,16 @@ const groups = computed(() => {
|
||||
</ComboboxInput>
|
||||
|
||||
<ComboboxPortal disabled>
|
||||
<ComboboxContent :class="ui.content()" :dismissable="false">
|
||||
<ComboboxEmpty :class="ui.empty()">
|
||||
<ComboboxContent :class="ui.content({ class: props.ui?.content })" :dismissable="false">
|
||||
<ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
|
||||
<slot name="empty" :search-term="searchTerm">
|
||||
{{ searchTerm ? `No results for ${searchTerm}` : 'No results' }}
|
||||
</slot>
|
||||
</ComboboxEmpty>
|
||||
|
||||
<ComboboxViewport :class="ui.viewport()">
|
||||
<ComboboxGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group()">
|
||||
<ComboboxLabel v-if="group.label" :class="ui.label()">
|
||||
<ComboboxViewport :class="ui.viewport({ class: props.ui?.viewport })">
|
||||
<ComboboxGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
|
||||
<ComboboxLabel v-if="group.label" :class="ui.label({ class: props.ui?.label })">
|
||||
{{ group.label }}
|
||||
</ComboboxLabel>
|
||||
|
||||
@@ -226,43 +227,43 @@ const groups = computed(() => {
|
||||
:key="`group-${groupIndex}-${index}`"
|
||||
:value="omit(item, ['matches' as any, 'group' as any, 'select', 'labelHtml', 'suffixHtml'])"
|
||||
:disabled="item.disabled"
|
||||
:class="ui.item()"
|
||||
:class="ui.item({ class: props.ui?.item })"
|
||||
@select="item.select"
|
||||
>
|
||||
<slot :name="item.slot || group.slot || 'item'" :item="item" :index="index">
|
||||
<slot :name="item.slot ? `${item.slot}-leading` : group.slot ? `${group.slot}-leading` : `item-leading`" :item="item" :index="index">
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.itemLeadingAvatar()" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon()" />
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: props.ui?.itemLeadingIcon })" />
|
||||
<UChip
|
||||
v-else-if="item.chip"
|
||||
size="md"
|
||||
inset
|
||||
standalone
|
||||
v-bind="item.chip"
|
||||
:class="ui.itemLeadingChip()"
|
||||
:class="ui.itemLeadingChip({ class: props.ui?.itemLeadingChip })"
|
||||
/>
|
||||
</slot>
|
||||
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label` : group.slot ? `${group.slot}-label` : `item-label`]" :class="ui.itemLabel()">
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label` : group.slot ? `${group.slot}-label` : `item-label`]" :class="ui.itemLabel({ class: props.ui?.itemLabel })">
|
||||
<slot :name="item.slot ? `${item.slot}-label` : group.slot ? `${group.slot}-label` : `item-label`" :item="item" :index="index">
|
||||
<span v-if="item.prefix" :class="ui.itemLabelPrefix()">{{ item.prefix }}</span>
|
||||
<span v-if="item.prefix" :class="ui.itemLabelPrefix({ class: props.ui?.itemLabelPrefix })">{{ item.prefix }}</span>
|
||||
|
||||
<span :class="ui.itemLabelBase()" v-html="item.labelHtml || item.label" />
|
||||
<span :class="ui.itemLabelBase({ class: props.ui?.itemLabelBase })" v-html="item.labelHtml || item.label" />
|
||||
|
||||
<span :class="ui.itemLabelSuffix()" v-html="item.suffixHtml || item.suffix" />
|
||||
<span :class="ui.itemLabelSuffix({ class: props.ui?.itemLabelSuffix })" v-html="item.suffixHtml || item.suffix" />
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span :class="ui.itemTrailing()">
|
||||
<span :class="ui.itemTrailing({ class: props.ui?.itemTrailing })">
|
||||
<slot :name="item.slot ? `${item.slot}-trailing` : group.slot ? `${group.slot}-trailing` : `item-trailing`" :item="item" :index="index">
|
||||
<span v-if="item.kbds?.length" :class="ui.itemTrailingKbds()">
|
||||
<span v-if="item.kbds?.length" :class="ui.itemTrailingKbds({ class: props.ui?.itemTrailingKbds })">
|
||||
<UKbd v-for="(kbd, kbdIndex) in item.kbds" :key="kbdIndex" size="md" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
|
||||
</span>
|
||||
<UIcon v-else-if="group.highlightedIcon" :name="group.highlightedIcon" :class="ui.itemTrailingHighlightedIcon()" />
|
||||
<UIcon v-else-if="group.highlightedIcon" :name="group.highlightedIcon" :class="ui.itemTrailingHighlightedIcon({ class: props.ui?.itemTrailingHighlightedIcon })" />
|
||||
</slot>
|
||||
|
||||
<ComboboxItemIndicator as-child>
|
||||
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon()" />
|
||||
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: props.ui?.itemTrailingIcon })" />
|
||||
</ComboboxItemIndicator>
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
@@ -76,7 +76,7 @@ const rootProps = useForwardPropsEmits(reactivePick(props, 'modal'), emits)
|
||||
const contentProps = toRef(() => props.content as ContextMenuContentProps)
|
||||
const proxySlots = omit(slots, ['default']) as Record<string, ContextMenuSlots<T>[string]>
|
||||
|
||||
const ui = computed(() => tv({ extend: contextMenu, slots: props.ui })({
|
||||
const ui = computed(() => contextMenu({
|
||||
size: props.size
|
||||
}))
|
||||
</script>
|
||||
@@ -87,7 +87,14 @@ const ui = computed(() => tv({ extend: contextMenu, slots: props.ui })({
|
||||
<slot />
|
||||
</ContextMenuTrigger>
|
||||
|
||||
<UContextMenuContent :class="ui.content({ class: props.class })" :ui="ui" v-bind="contentProps" :items="items" :portal="portal">
|
||||
<UContextMenuContent
|
||||
:class="ui.content({ class: props.class })"
|
||||
:ui="ui"
|
||||
:ui-override="props.ui"
|
||||
v-bind="contentProps"
|
||||
:items="items"
|
||||
:portal="portal"
|
||||
>
|
||||
<template v-for="(_, name) in proxySlots" #[name]="slotData: any">
|
||||
<slot :name="name" v-bind="slotData" />
|
||||
</template>
|
||||
|
||||
@@ -12,6 +12,7 @@ interface ContextMenuContentProps<T> extends Omit<RadixContextMenuContentProps,
|
||||
sub?: boolean
|
||||
class?: any
|
||||
ui: typeof contextMenu
|
||||
uiOverride?: any
|
||||
}
|
||||
|
||||
interface ContextMenuContentEmits extends RadixContextMenuContentEmits {}
|
||||
@@ -44,22 +45,22 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
<DefineItemTemplate v-slot="{ item, active, index }">
|
||||
<slot :name="item.slot || 'item'" :item="(item as T)" :index="index">
|
||||
<slot :name="item.slot ? `${item.slot}-leading`: 'item-leading'" :item="(item as T)" :active="active" :index="index">
|
||||
<UAvatar v-if="item.avatar" :size="(ui.itemLeadingAvatarSize() as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ active })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ active })" />
|
||||
<UAvatar v-if="item.avatar" :size="(ui.itemLeadingAvatarSize() as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: uiOverride?.itemLeadingAvatar, active })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: uiOverride?.itemLeadingIcon, active })" />
|
||||
</slot>
|
||||
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label`: 'item-label']" :class="ui.itemLabel({ active })">
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label`: 'item-label']" :class="ui.itemLabel({ class: uiOverride?.itemLabel, active })">
|
||||
<slot :name="item.slot ? `${item.slot}-label`: 'item-label'" :item="(item as T)" :active="active" :index="index">
|
||||
{{ item.label }}
|
||||
</slot>
|
||||
|
||||
<UIcon v-if="item.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.itemLabelExternalIcon({ active })" />
|
||||
<UIcon v-if="item.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.itemLabelExternalIcon({ class: uiOverride?.itemLabelExternalIcon, active })" />
|
||||
</span>
|
||||
|
||||
<span v-if="item.children?.length || item.kbds?.length || !!slots[item.slot ? `${item.slot}-trailing`: 'item-trailing']" :class="ui.itemTrailing()">
|
||||
<span v-if="item.children?.length || item.kbds?.length || !!slots[item.slot ? `${item.slot}-trailing`: 'item-trailing']" :class="ui.itemTrailing({ class: uiOverride?.itemTrailing })">
|
||||
<slot :name="item.slot ? `${item.slot}-trailing`: 'item-trailing'" :item="(item as T)" :active="active" :index="index">
|
||||
<UIcon v-if="item.children?.length" :name="appConfig.ui.icons.chevronRight" :class="ui.itemTrailingIcon({ active })" />
|
||||
<span v-else-if="item.kbds?.length" :class="ui.itemTrailingKbds()">
|
||||
<UIcon v-if="item.children?.length" :name="appConfig.ui.icons.chevronRight" :class="ui.itemTrailingIcon({ class: uiOverride?.itemTrailingIcon, active })" />
|
||||
<span v-else-if="item.kbds?.length" :class="ui.itemTrailingKbds({ class: uiOverride?.itemTrailingKbds })">
|
||||
<UKbd v-for="(kbd, kbdIndex) in item.kbds" :key="kbdIndex" :size="(ui.itemTrailingKbdsSize() as KbdProps['size'])" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
|
||||
</span>
|
||||
</slot>
|
||||
@@ -69,12 +70,12 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
|
||||
<ContextMenu.Portal :disabled="!portal">
|
||||
<component :is="sub ? ContextMenu.SubContent : ContextMenu.Content" :class="props.class" v-bind="contentProps">
|
||||
<ContextMenu.Group v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group()">
|
||||
<ContextMenu.Group v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: uiOverride?.group })">
|
||||
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
|
||||
<ContextMenu.Label v-if="item.type === 'label'" :class="ui.label()">
|
||||
<ContextMenu.Label v-if="item.type === 'label'" :class="ui.label({ class: uiOverride?.label })">
|
||||
<ReuseItemTemplate :item="item" :index="index" />
|
||||
</ContextMenu.Label>
|
||||
<ContextMenu.Separator v-else-if="item.type === 'separator'" :class="ui.separator()" />
|
||||
<ContextMenu.Separator v-else-if="item.type === 'separator'" :class="ui.separator({ class: uiOverride?.separator })" />
|
||||
<ContextMenu.Sub v-else-if="item?.children?.length">
|
||||
<ContextMenu.SubTrigger
|
||||
as="button"
|
||||
@@ -83,7 +84,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
:open="item.open"
|
||||
:default-open="item.defaultOpen"
|
||||
:text-value="item.label"
|
||||
:class="ui.item()"
|
||||
:class="ui.item({ class: uiOverride?.item })"
|
||||
>
|
||||
<ReuseItemTemplate :item="item" :index="index" />
|
||||
</ContextMenu.SubTrigger>
|
||||
@@ -92,6 +93,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
sub
|
||||
:class="props.class"
|
||||
:ui="ui"
|
||||
:ui-override="uiOverride"
|
||||
:portal="portal"
|
||||
:items="item.children"
|
||||
:align-offset="-4"
|
||||
@@ -104,7 +106,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
</ContextMenu.Sub>
|
||||
<ContextMenu.Item v-else as-child :disabled="item.disabled" :text-value="item.label" @select="item.select">
|
||||
<ULink v-slot="{ active, ...slotProps }" v-bind="pickLinkProps(item as Omit<ContextMenuItem, 'type'>)" custom>
|
||||
<ULinkBase v-bind="slotProps" :class="ui.item({ active })">
|
||||
<ULinkBase v-bind="slotProps" :class="ui.item({ class: uiOverride?.item, active })">
|
||||
<ReuseItemTemplate :item="item" :active="active" :index="index" />
|
||||
</ULinkBase>
|
||||
</ULink>
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface DrawerSlots {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, toRef } from 'vue'
|
||||
import { toRef } from 'vue'
|
||||
import { useForwardPropsEmits } from 'radix-vue'
|
||||
import { DrawerRoot, DrawerTrigger, DrawerPortal, DrawerOverlay, DrawerContent, DrawerTitle, DrawerDescription } from 'vaul-vue'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
@@ -60,7 +60,8 @@ const slots = defineSlots<DrawerSlots>()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'activeSnapPoint', 'closeThreshold', 'defaultOpen', 'dismissible', 'fadeFromIndex', 'fixed', 'modal', 'nested', 'open', 'scrollLockTimeout', 'shouldScaleBackground', 'snapPoints'), emits)
|
||||
const contentProps = toRef(() => props.content)
|
||||
|
||||
const ui = computed(() => tv({ extend: drawer, slots: props.ui })())
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = drawer()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -70,24 +71,24 @@ const ui = computed(() => tv({ extend: drawer, slots: props.ui })())
|
||||
</DrawerTrigger>
|
||||
|
||||
<DrawerPortal :disabled="!portal">
|
||||
<DrawerOverlay v-if="overlay" :class="ui.overlay()" />
|
||||
<DrawerOverlay v-if="overlay" :class="ui.overlay({ class: props.ui?.overlay })" />
|
||||
|
||||
<DrawerContent :class="ui.content({ class: props.class })" v-bind="contentProps">
|
||||
<slot name="handle">
|
||||
<div :class="ui.handle()" />
|
||||
<div :class="ui.handle({ class: props.ui?.handle })" />
|
||||
</slot>
|
||||
|
||||
<slot name="content">
|
||||
<div :class="ui.container()">
|
||||
<div v-if="!!slots.header || (title || !!slots.title) || (description || !!slots.description)" :class="ui.header()">
|
||||
<div :class="ui.container({ class: props.ui?.container })">
|
||||
<div v-if="!!slots.header || (title || !!slots.title) || (description || !!slots.description)" :class="ui.header({ class: props.ui?.header })">
|
||||
<slot name="header">
|
||||
<DrawerTitle v-if="title || !!slots.title" :class="ui.title()">
|
||||
<DrawerTitle v-if="title || !!slots.title" :class="ui.title({ class: props.ui?.title })">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</DrawerTitle>
|
||||
|
||||
<DrawerDescription v-if="description || !!slots.description" :class="ui.description()">
|
||||
<DrawerDescription v-if="description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
@@ -95,11 +96,11 @@ const ui = computed(() => tv({ extend: drawer, slots: props.ui })())
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<div v-if="!!slots.body" :class="ui.body()">
|
||||
<div v-if="!!slots.body" :class="ui.body({ class: props.ui?.body })">
|
||||
<slot name="body" />
|
||||
</div>
|
||||
|
||||
<div v-if="!!slots.footer" :class="ui.footer()">
|
||||
<div v-if="!!slots.footer" :class="ui.footer({ class: props.ui?.footer })">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -86,7 +86,7 @@ const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffse
|
||||
const arrowProps = toRef(() => props.arrow as DropdownMenuArrowProps)
|
||||
const proxySlots = omit(slots, ['default']) as Record<string, DropdownMenuSlots<T>[string]>
|
||||
|
||||
const ui = computed(() => tv({ extend: dropdownMenu, slots: props.ui })({
|
||||
const ui = computed(() => dropdownMenu({
|
||||
size: props.size
|
||||
}))
|
||||
</script>
|
||||
@@ -97,12 +97,19 @@ const ui = computed(() => tv({ extend: dropdownMenu, slots: props.ui })({
|
||||
<slot :open="open" />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<UDropdownMenuContent :class="ui.content({ class: props.class })" :ui="ui" v-bind="contentProps" :items="items" :portal="portal">
|
||||
<UDropdownMenuContent
|
||||
:class="ui.content({ class: props.class })"
|
||||
:ui="ui"
|
||||
:ui-override="props.ui"
|
||||
v-bind="contentProps"
|
||||
:items="items"
|
||||
:portal="portal"
|
||||
>
|
||||
<template v-for="(_, name) in proxySlots" #[name]="slotData: any">
|
||||
<slot :name="name" v-bind="slotData" />
|
||||
</template>
|
||||
|
||||
<DropdownMenuArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow()" />
|
||||
<DropdownMenuArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
|
||||
</UDropdownMenuContent>
|
||||
</DropdownMenuRoot>
|
||||
</template>
|
||||
|
||||
@@ -12,6 +12,7 @@ interface DropdownMenuContentProps<T> extends Omit<RadixDropdownMenuContentProps
|
||||
sub?: boolean
|
||||
class?: any
|
||||
ui: typeof dropdownMenu
|
||||
uiOverride?: any
|
||||
}
|
||||
|
||||
interface DropdownMenuContentEmits extends RadixDropdownMenuContentEmits {}
|
||||
@@ -48,22 +49,22 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
<DefineItemTemplate v-slot="{ item, active, index }">
|
||||
<slot :name="item.slot || 'item'" :item="(item as T)" :index="index">
|
||||
<slot :name="item.slot ? `${item.slot}-leading`: 'item-leading'" :item="(item as T)" :active="active" :index="index">
|
||||
<UAvatar v-if="item.avatar" :size="(ui.itemLeadingAvatarSize() as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ active })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ active })" />
|
||||
<UAvatar v-if="item.avatar" :size="(ui.itemLeadingAvatarSize() as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: uiOverride?.itemLeadingAvatar, active })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: uiOverride?.itemLeadingIcon, active })" />
|
||||
</slot>
|
||||
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label`: 'item-label']" :class="ui.itemLabel({ active })">
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label`: 'item-label']" :class="ui.itemLabel({ class: uiOverride?.itemLabel, active })">
|
||||
<slot :name="item.slot ? `${item.slot}-label`: 'item-label'" :item="(item as T)" :active="active" :index="index">
|
||||
{{ item.label }}
|
||||
</slot>
|
||||
|
||||
<UIcon v-if="item.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.itemLabelExternalIcon({ active })" />
|
||||
<UIcon v-if="item.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.itemLabelExternalIcon({ class: uiOverride?.itemLabelExternalIcon, active })" />
|
||||
</span>
|
||||
|
||||
<span v-if="item.children?.length || item.kbds?.length || !!slots[item.slot ? `${item.slot}-trailing`: 'item-trailing']" :class="ui.itemTrailing()">
|
||||
<span v-if="item.children?.length || item.kbds?.length || !!slots[item.slot ? `${item.slot}-trailing`: 'item-trailing']" :class="ui.itemTrailing({ class: uiOverride?.itemTrailing })">
|
||||
<slot :name="item.slot ? `${item.slot}-trailing`: 'item-trailing'" :item="(item as T)" :active="active" :index="index">
|
||||
<UIcon v-if="item.children?.length" :name="appConfig.ui.icons.chevronRight" :class="ui.itemTrailingIcon({ active })" />
|
||||
<span v-else-if="item.kbds?.length" :class="ui.itemTrailingKbds()">
|
||||
<UIcon v-if="item.children?.length" :name="appConfig.ui.icons.chevronRight" :class="ui.itemTrailingIcon({ class: uiOverride?.itemTrailingIcon, active })" />
|
||||
<span v-else-if="item.kbds?.length" :class="ui.itemTrailingKbds({ class: uiOverride?.itemTrailingKbds })">
|
||||
<UKbd v-for="(kbd, kbdIndex) in item.kbds" :key="kbdIndex" :size="(ui.itemTrailingKbdsSize() as KbdProps['size'])" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
|
||||
</span>
|
||||
</slot>
|
||||
@@ -73,12 +74,12 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
|
||||
<DropdownMenu.Portal :disabled="!portal">
|
||||
<component :is="sub ? DropdownMenu.SubContent : DropdownMenu.Content" :class="props.class" v-bind="contentProps">
|
||||
<DropdownMenu.Group v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group()">
|
||||
<DropdownMenu.Group v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: uiOverride?.group })">
|
||||
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
|
||||
<DropdownMenu.Label v-if="item.type === 'label'" :class="ui.label()">
|
||||
<DropdownMenu.Label v-if="item.type === 'label'" :class="ui.label({ class: uiOverride?.label })">
|
||||
<ReuseItemTemplate :item="item" :index="index" />
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator v-else-if="item.type === 'separator'" :class="ui.separator()" />
|
||||
<DropdownMenu.Separator v-else-if="item.type === 'separator'" :class="ui.separator({ class: uiOverride?.separator })" />
|
||||
<DropdownMenu.Sub v-else-if="item?.children?.length">
|
||||
<DropdownMenu.SubTrigger
|
||||
as="button"
|
||||
@@ -87,7 +88,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
:open="item.open"
|
||||
:default-open="item.defaultOpen"
|
||||
:text-value="item.label"
|
||||
:class="ui.item()"
|
||||
:class="ui.item({ class: uiOverride?.item })"
|
||||
>
|
||||
<ReuseItemTemplate :item="item" :index="index" />
|
||||
</DropdownMenu.SubTrigger>
|
||||
@@ -96,6 +97,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
sub
|
||||
:class="props.class"
|
||||
:ui="ui"
|
||||
:ui-override="uiOverride"
|
||||
:portal="portal"
|
||||
:items="item.children"
|
||||
side="right"
|
||||
@@ -111,7 +113,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
</DropdownMenu.Sub>
|
||||
<DropdownMenu.Item v-else as-child :disabled="item.disabled" :text-value="item.label" @select="item.select">
|
||||
<ULink v-slot="{ active, ...slotProps }" v-bind="pickLinkProps(item as Omit<DropdownMenuItem, 'type'>)" custom>
|
||||
<ULinkBase v-bind="slotProps" :class="ui.item({ active })">
|
||||
<ULinkBase v-bind="slotProps" :class="ui.item({ class: uiOverride?.item, active })">
|
||||
<ReuseItemTemplate :item="item" :active="active" :index="index" />
|
||||
</ULinkBase>
|
||||
</ULink>
|
||||
|
||||
@@ -44,7 +44,7 @@ import type { FormError } from '../types/form'
|
||||
const props = defineProps<FormFieldProps>()
|
||||
const slots = defineSlots<FormFieldSlots>()
|
||||
|
||||
const ui = computed(() => tv({ extend: formField, slots: props.ui })({
|
||||
const ui = computed(() => formField({
|
||||
size: props.size,
|
||||
required: props.required
|
||||
}))
|
||||
@@ -72,21 +72,21 @@ provide(formFieldInjectionKey, computed(() => ({
|
||||
|
||||
<template>
|
||||
<div :class="ui.root({ class: props.class })">
|
||||
<div :class="ui.wrapper()">
|
||||
<div v-if="label || !!slots.label" :class="ui.labelWrapper()">
|
||||
<Label :for="id" :class="ui.label()">
|
||||
<div :class="ui.wrapper({ class: props.ui?.wrapper })">
|
||||
<div v-if="label || !!slots.label" :class="ui.labelWrapper({ class: props.ui?.labelWrapper })">
|
||||
<Label :for="id" :class="ui.label({ class: props.ui?.label })">
|
||||
<slot name="label" :label="label">
|
||||
{{ label }}
|
||||
</slot>
|
||||
</Label>
|
||||
<span v-if="hint || !!slots.hint" :class="ui.hint()">
|
||||
<span v-if="hint || !!slots.hint" :class="ui.hint({ class: props.ui?.hint })">
|
||||
<slot name="hint" :hint="hint">
|
||||
{{ hint }}
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p v-if="description || !!slots.description" :class="ui.description()">
|
||||
<p v-if="description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description" :description="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
@@ -96,12 +96,12 @@ provide(formFieldInjectionKey, computed(() => ({
|
||||
<div :class="[label && ui.container()]">
|
||||
<slot :error="error" />
|
||||
|
||||
<p v-if="(typeof error === 'string' && error) || !!slots.error" :class="ui.error()">
|
||||
<p v-if="(typeof error === 'string' && error) || !!slots.error" :class="ui.error({ class: props.ui?.error })">
|
||||
<slot name="error" :error="error">
|
||||
{{ error }}
|
||||
</slot>
|
||||
</p>
|
||||
<p v-else-if="help || !!slots.help" :class="ui.help()">
|
||||
<p v-else-if="help || !!slots.help" :class="ui.help({ class: props.ui?.help })">
|
||||
<slot name="help" :help="help">
|
||||
{{ help }}
|
||||
</slot>
|
||||
|
||||
@@ -65,7 +65,7 @@ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponen
|
||||
|
||||
const inputSize = computed(() => buttonGroupSize.value || formGroupSize.value)
|
||||
|
||||
const ui = computed(() => tv({ extend: input, slots: props.ui })({
|
||||
const ui = computed(() => input({
|
||||
type: props.type as InputVariants['type'],
|
||||
color: color.value,
|
||||
variant: props.variant,
|
||||
@@ -141,7 +141,7 @@ onMounted(() => {
|
||||
:value="modelValue"
|
||||
:name="name"
|
||||
:placeholder="placeholder"
|
||||
:class="ui.base()"
|
||||
:class="ui.base({ class: props.ui?.base })"
|
||||
:disabled="disabled"
|
||||
:required="required"
|
||||
v-bind="$attrs"
|
||||
@@ -152,15 +152,15 @@ onMounted(() => {
|
||||
|
||||
<slot />
|
||||
|
||||
<span v-if="isLeading || !!slots.leading" :class="ui.leading()">
|
||||
<span v-if="isLeading || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
||||
<slot name="leading">
|
||||
<UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon()" />
|
||||
<UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span v-if="isTrailing || !!slots.trailing" :class="ui.trailing()">
|
||||
<span v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })">
|
||||
<slot name="trailing">
|
||||
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon()" />
|
||||
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -137,7 +137,7 @@ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponen
|
||||
|
||||
const inputSize = computed(() => buttonGroupSize.value || formGroupSize.value)
|
||||
|
||||
const ui = computed(() => tv({ extend: inputMenu, slots: props.ui })({
|
||||
const ui = computed(() => inputMenu({
|
||||
color: color.value,
|
||||
variant: props.variant,
|
||||
size: inputSize?.value,
|
||||
@@ -233,7 +233,7 @@ function onUpdateOpen(value: boolean) {
|
||||
@update:open="onUpdateOpen"
|
||||
@keydown.enter="$event.preventDefault()"
|
||||
>
|
||||
<ComboboxAnchor :as-child="!multiple" :class="ui.base()">
|
||||
<ComboboxAnchor :as-child="!multiple" :class="ui.base({ class: props.ui?.base })">
|
||||
<TagsInputRoot
|
||||
v-if="multiple"
|
||||
v-slot="{ modelValue: tags }: { modelValue: AcceptableValue[] }"
|
||||
@@ -243,16 +243,16 @@ function onUpdateOpen(value: boolean) {
|
||||
as-child
|
||||
@blur="onBlur"
|
||||
>
|
||||
<TagsInputItem v-for="(item, index) in tags" :key="index" :value="(item as string)" :class="ui.tagsItem()">
|
||||
<TagsInputItemText :class="ui.tagsItemText()">
|
||||
<TagsInputItem v-for="(item, index) in tags" :key="index" :value="(item as string)" :class="ui.tagsItem({ class: props.ui?.tagsItem })">
|
||||
<TagsInputItemText :class="ui.tagsItemText({ class: props.ui?.tagsItemText })">
|
||||
<slot name="tags-item-text" :item="(item as T)" :index="index">
|
||||
{{ typeof item === 'object' ? item.label : item }}
|
||||
</slot>
|
||||
</TagsInputItemText>
|
||||
|
||||
<TagsInputItemDelete :class="ui.tagsItemDelete()" :disabled="disabled">
|
||||
<TagsInputItemDelete :class="ui.tagsItemDelete({ class: props.ui?.tagsItemDelete })" :disabled="disabled">
|
||||
<slot name="tags-item-delete" :item="(item as T)" :index="index">
|
||||
<UIcon :name="deleteIcon || appConfig.ui.icons.close" :class="ui.tagsItemDeleteIcon()" />
|
||||
<UIcon :name="deleteIcon || appConfig.ui.icons.close" :class="ui.tagsItemDeleteIcon({ class: props.ui?.tagsItemDeleteIcon })" />
|
||||
</slot>
|
||||
</TagsInputItemDelete>
|
||||
</TagsInputItem>
|
||||
@@ -263,7 +263,7 @@ function onUpdateOpen(value: boolean) {
|
||||
v-bind="$attrs"
|
||||
:placeholder="placeholder"
|
||||
:required="required"
|
||||
:class="ui.tagsInput()"
|
||||
:class="ui.tagsInput({ class: props.ui?.tagsInput })"
|
||||
@keydown.enter.prevent
|
||||
/>
|
||||
</ComboboxInput>
|
||||
@@ -276,66 +276,66 @@ function onUpdateOpen(value: boolean) {
|
||||
:type="type"
|
||||
:placeholder="placeholder"
|
||||
:required="required"
|
||||
:class="ui.base()"
|
||||
:class="ui.base({ class: props.ui?.base })"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
|
||||
<span v-if="isLeading || !!slots.leading" :class="ui.leading()">
|
||||
<span v-if="isLeading || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
||||
<slot name="leading" :model-value="(modelValue as T)" :open="open" :ui="ui">
|
||||
<UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon()" />
|
||||
<UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<ComboboxTrigger v-if="isTrailing || !!slots.trailing" :class="ui.trailing()">
|
||||
<ComboboxTrigger v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })">
|
||||
<slot name="trailing" :model-value="(modelValue as T)" :open="open" :ui="ui">
|
||||
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon()" />
|
||||
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
|
||||
</slot>
|
||||
</ComboboxTrigger>
|
||||
</ComboboxAnchor>
|
||||
|
||||
<ComboboxPortal :disabled="!portal">
|
||||
<ComboboxContent :class="ui.content()" v-bind="contentProps">
|
||||
<ComboboxEmpty :class="ui.empty()">
|
||||
<ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
|
||||
<ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
|
||||
<slot name="empty" :search-term="searchTerm">
|
||||
{{ searchTerm ? `No results for ${searchTerm}` : 'No results' }}
|
||||
</slot>
|
||||
</ComboboxEmpty>
|
||||
|
||||
<ComboboxViewport :class="ui.viewport()">
|
||||
<ComboboxGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group()">
|
||||
<ComboboxViewport :class="ui.viewport({ class: props.ui?.viewport })">
|
||||
<ComboboxGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
|
||||
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
|
||||
<ComboboxLabel v-if="item?.type === 'label'" :class="ui.label()">
|
||||
<ComboboxLabel v-if="item?.type === 'label'" :class="ui.label({ class: props.ui?.label })">
|
||||
{{ item.label }}
|
||||
</ComboboxLabel>
|
||||
|
||||
<ComboboxSeparator v-else-if="item?.type === 'separator'" :class="ui.separator()" />
|
||||
<ComboboxSeparator v-else-if="item?.type === 'separator'" :class="ui.separator({ class: props.ui?.separator })" />
|
||||
|
||||
<ComboboxItem v-else :class="ui.item()" :disabled="item.disabled" :value="item">
|
||||
<ComboboxItem v-else :class="ui.item({ class: props.ui?.item })" :disabled="item.disabled" :value="item">
|
||||
<slot name="item" :item="(item as T)" :index="index">
|
||||
<slot name="item-leading" :item="(item as T)" :index="index">
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.itemLeadingAvatar()" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon()" />
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: props.ui?.itemLeadingIcon })" />
|
||||
<UChip
|
||||
v-else-if="item.chip"
|
||||
size="md"
|
||||
inset
|
||||
standalone
|
||||
v-bind="item.chip"
|
||||
:class="ui.itemLeadingChip()"
|
||||
:class="ui.itemLeadingChip({ class: props.ui?.itemLeadingChip })"
|
||||
/>
|
||||
</slot>
|
||||
|
||||
<span :class="ui.itemLabel()">
|
||||
<span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
|
||||
<slot name="item-label" :item="(item as T)" :index="index">
|
||||
{{ displayValue(item as T) }}
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span :class="ui.itemTrailing()">
|
||||
<span :class="ui.itemTrailing({ class: props.ui?.itemTrailing })">
|
||||
<slot name="item-trailing" :item="(item as T)" :index="index" />
|
||||
|
||||
<ComboboxItemIndicator as-child>
|
||||
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon()" />
|
||||
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: props.ui?.itemTrailingIcon })" />
|
||||
</ComboboxItemIndicator>
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
@@ -48,7 +48,7 @@ export interface ModalSlots {
|
||||
header(props?: {}): any
|
||||
title(props?: {}): any
|
||||
description(props?: {}): any
|
||||
close(props: { class: string }): any
|
||||
close(props: { ui: any }): any
|
||||
body(props?: {}): any
|
||||
footer(props?: {}): any
|
||||
}
|
||||
@@ -85,7 +85,7 @@ const contentEvents = computed(() => {
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed(() => tv({ extend: modal, slots: props.ui })({
|
||||
const ui = computed(() => modal({
|
||||
transition: props.transition,
|
||||
fullscreen: props.fullscreen
|
||||
}))
|
||||
@@ -98,26 +98,26 @@ const ui = computed(() => tv({ extend: modal, slots: props.ui })({
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogPortal :disabled="!portal">
|
||||
<DialogOverlay v-if="overlay" :class="ui.overlay()" />
|
||||
<DialogOverlay v-if="overlay" :class="ui.overlay({ class: props.ui?.overlay })" />
|
||||
|
||||
<DialogContent :class="ui.content({ class: props.class })" v-bind="contentProps" v-on="contentEvents">
|
||||
<slot name="content">
|
||||
<div v-if="!!slots.header || (title || !!slots.title) || (description || !!slots.description) || (close || !!slots.close)" :class="ui.header()">
|
||||
<div v-if="!!slots.header || (title || !!slots.title) || (description || !!slots.description) || (close || !!slots.close)" :class="ui.header({ class: props.ui?.header })">
|
||||
<slot name="header">
|
||||
<DialogTitle v-if="title || !!slots.title" :class="ui.title()">
|
||||
<DialogTitle v-if="title || !!slots.title" :class="ui.title({ class: props.ui?.title })">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogDescription v-if="description || !!slots.description" :class="ui.description()">
|
||||
<DialogDescription v-if="description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
</DialogDescription>
|
||||
|
||||
<DialogClose as-child>
|
||||
<slot name="close" :class="ui.close()">
|
||||
<slot name="close" :ui="ui">
|
||||
<UButton
|
||||
v-if="close"
|
||||
:icon="closeIcon || appConfig.ui.icons.close"
|
||||
@@ -126,18 +126,18 @@ const ui = computed(() => tv({ extend: modal, slots: props.ui })({
|
||||
variant="ghost"
|
||||
aria-label="Close"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close()"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
/>
|
||||
</slot>
|
||||
</DialogClose>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<div v-if="!!slots.body" :class="ui.body()">
|
||||
<div v-if="!!slots.body" :class="ui.body({ class: props.ui?.body })">
|
||||
<slot name="body" />
|
||||
</div>
|
||||
|
||||
<div v-if="!!slots.footer" :class="ui.footer()">
|
||||
<div v-if="!!slots.footer" :class="ui.footer({ class: props.ui?.footer })">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</slot>
|
||||
|
||||
@@ -93,7 +93,7 @@ const slots = defineSlots<NavigationMenuSlots<T>>()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'delayDuration', 'skipDelayDuration', 'orientation'), emits)
|
||||
const contentProps = toRef(() => props.content)
|
||||
|
||||
const ui = computed(() => tv({ extend: navigationMenu, slots: props.ui })({
|
||||
const ui = computed(() => navigationMenu({
|
||||
orientation: props.orientation,
|
||||
color: props.color,
|
||||
variant: props.variant,
|
||||
@@ -107,8 +107,8 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
|
||||
<template>
|
||||
<NavigationMenuRoot v-bind="rootProps" :class="ui.root({ class: props.class })">
|
||||
<template v-for="(list, listIndex) in lists" :key="`list-${listIndex}`">
|
||||
<NavigationMenuList :class="ui.list()">
|
||||
<NavigationMenuItem v-for="(item, index) in list" :key="`list-${listIndex}-${index}`" :value="item.value || String(index)" :class="ui.item()">
|
||||
<NavigationMenuList :class="ui.list({ class: props.ui?.list })">
|
||||
<NavigationMenuItem v-for="(item, index) in list" :key="`list-${listIndex}-${index}`" :value="item.value || String(index)" :class="ui.item({ class: props.ui?.item })">
|
||||
<ULink v-slot="{ active, ...slotProps }" v-bind="pickLinkProps(item)" custom>
|
||||
<component
|
||||
:is="item.children?.length ? NavigationMenuTrigger : NavigationMenuLink"
|
||||
@@ -117,52 +117,52 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
|
||||
:active="active"
|
||||
@select="item.select"
|
||||
>
|
||||
<ULinkBase v-bind="slotProps" :class="ui.link({ active, disabled: !!item.disabled })">
|
||||
<ULinkBase v-bind="slotProps" :class="ui.link({ class: props.ui?.link, active, disabled: !!item.disabled })">
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<slot :name="item.slot ? `${item.slot}-leading`: 'item-leading'" :item="item" :active="active" :index="index">
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ active, disabled: !!item.disabled })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ active, disabled: !!item.disabled })" />
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ class: props.ui?.linkLeadingAvatar, active, disabled: !!item.disabled })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ class: props.ui?.linkLeadingIcon, active, disabled: !!item.disabled })" />
|
||||
</slot>
|
||||
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label`: 'item-label']" :class="ui.linkLabel()">
|
||||
<span v-if="item.label || !!slots[item.slot ? `${item.slot}-label`: 'item-label']" :class="ui.linkLabel({ class: props.ui?.linkLabel })">
|
||||
<slot :name="item.slot ? `${item.slot}-label`: 'item-label'" :item="item" :active="active" :index="index">
|
||||
{{ item.label }}
|
||||
</slot>
|
||||
|
||||
<UIcon v-if="item.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.linkLabelExternalIcon({ active })" />
|
||||
<UIcon v-if="item.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.linkLabelExternalIcon({ class: props.ui?.linkLabelExternalIcon, active })" />
|
||||
</span>
|
||||
|
||||
<span v-if="item.badge || (item.children?.length && orientation === 'horizontal') || !!slots[item.slot ? `${item.slot}-trailing`: 'item-trailing']" :class="ui.linkTrailing()">
|
||||
<span v-if="item.badge || (item.children?.length && orientation === 'horizontal') || !!slots[item.slot ? `${item.slot}-trailing`: 'item-trailing']" :class="ui.linkTrailing({ class: props.ui?.linkTrailing })">
|
||||
<slot :name="item.slot ? `${item.slot}-trailing`: 'item-trailing'" :item="item" :active="active" :index="index">
|
||||
<UBadge
|
||||
v-if="item.badge"
|
||||
color="white"
|
||||
size="sm"
|
||||
v-bind="(typeof item.badge === 'string' || typeof item.badge === 'number') ? { label: item.badge } : item.badge"
|
||||
:class="ui.linkTrailingBadge()"
|
||||
:class="ui.linkTrailingBadge({ class: props.ui?.linkTrailingBadge })"
|
||||
/>
|
||||
<UIcon v-if="item.children?.length && orientation === 'horizontal'" :name="item.trailingIcon || trailingIcon || appConfig.ui.icons.chevronDown" :class="ui.linkTrailingIcon({ active })" />
|
||||
<UIcon v-if="item.children?.length && orientation === 'horizontal'" :name="item.trailingIcon || trailingIcon || appConfig.ui.icons.chevronDown" :class="ui.linkTrailingIcon({ class: props.ui?.linkTrailingIcon, active })" />
|
||||
</slot>
|
||||
</span>
|
||||
</slot>
|
||||
</ULinkBase>
|
||||
</component>
|
||||
|
||||
<NavigationMenuContent v-if="item.children?.length && orientation === 'horizontal'" v-bind="contentProps" :class="ui.content()">
|
||||
<ul :class="ui.childList()">
|
||||
<li v-for="(childItem, childIndex) in item.children" :key="childIndex" :class="ui.childItem()">
|
||||
<NavigationMenuContent v-if="item.children?.length && orientation === 'horizontal'" v-bind="contentProps" :class="ui.content({ class: props.ui?.content })">
|
||||
<ul :class="ui.childList({ class: props.ui?.childList })">
|
||||
<li v-for="(childItem, childIndex) in item.children" :key="childIndex" :class="ui.childItem({ class: props.ui?.childItem })">
|
||||
<ULink v-slot="{ active: childActive, ...childSlotProps }" v-bind="pickLinkProps(childItem)" custom>
|
||||
<NavigationMenuLink as-child :active="childActive" @select="childItem.select">
|
||||
<ULinkBase v-bind="childSlotProps" :class="ui.childLink({ active: childActive })">
|
||||
<UIcon v-if="childItem.icon" :name="childItem.icon" :class="ui.childLinkIcon({ active: childActive })" />
|
||||
<ULinkBase v-bind="childSlotProps" :class="ui.childLink({ class: props.ui?.childLink, active: childActive })">
|
||||
<UIcon v-if="childItem.icon" :name="childItem.icon" :class="ui.childLinkIcon({ class: props.ui?.childLinkIcon, active: childActive })" />
|
||||
|
||||
<div :class="ui.childLinkWrapper()">
|
||||
<p :class="ui.childLinkLabel({ active: childActive })">
|
||||
<div :class="ui.childLinkWrapper({ class: props.ui?.childLinkWrapper })">
|
||||
<p :class="ui.childLinkLabel({ class: props.ui?.childLinkLabel, active: childActive })">
|
||||
{{ childItem.label }}
|
||||
|
||||
<UIcon v-if="childItem.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.childLinkLabelExternalIcon({ active: childActive })" />
|
||||
<UIcon v-if="childItem.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.childLinkLabelExternalIcon({ class: props.ui?.childLinkLabelExternalIcon, active: childActive })" />
|
||||
</p>
|
||||
<p v-if="childItem.description" :class="ui.childLinkDescription({ active: childActive })">
|
||||
<p v-if="childItem.description" :class="ui.childLinkDescription({ class: props.ui?.childLinkDescription, active: childActive })">
|
||||
{{ childItem.description }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -176,15 +176,15 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuList>
|
||||
|
||||
<div v-if="orientation === 'vertical' && listIndex < lists.length - 1" :class="ui.separator()" />
|
||||
<div v-if="orientation === 'vertical' && listIndex < lists.length - 1" :class="ui.separator({ class: props.ui?.separator })" />
|
||||
</template>
|
||||
|
||||
<div v-if="orientation === 'horizontal'" :class="ui.viewportWrapper()">
|
||||
<NavigationMenuIndicator v-if="arrow" :class="ui.indicator()">
|
||||
<div :class="ui.arrow()" />
|
||||
<div v-if="orientation === 'horizontal'" :class="ui.viewportWrapper({ class: props.ui?.viewportWrapper })">
|
||||
<NavigationMenuIndicator v-if="arrow" :class="ui.indicator({ class: props.ui?.indicator })">
|
||||
<div :class="ui.arrow({ class: props.ui?.arrow })" />
|
||||
</NavigationMenuIndicator>
|
||||
|
||||
<NavigationMenuViewport :class="ui.viewport()" />
|
||||
<NavigationMenuViewport :class="ui.viewport({ class: props.ui?.viewport })" />
|
||||
</div>
|
||||
</NavigationMenuRoot>
|
||||
</template>
|
||||
|
||||
@@ -100,7 +100,6 @@ export interface PaginationSlots {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { PaginationRoot, PaginationList, PaginationListItem, PaginationFirst, PaginationPrev, PaginationEllipsis, PaginationNext, PaginationLast, useForwardPropsEmits } from 'radix-vue'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
import { useAppConfig } from '#imports'
|
||||
@@ -119,12 +118,13 @@ const appConfig = useAppConfig()
|
||||
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultPage', 'disabled', 'itemsPerPage', 'page', 'showEdges', 'siblingCount', 'total'), emits)
|
||||
|
||||
const ui = computed(() => tv({ extend: pagination, slots: props.ui })())
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = pagination()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationRoot v-slot="{ page, pageCount }" v-bind="rootProps" :class="ui.root({ class: props.class })">
|
||||
<PaginationList v-slot="{ items }" :class="ui.list()">
|
||||
<PaginationList v-slot="{ items }" :class="ui.list({ class: props.ui?.list })">
|
||||
<PaginationFirst v-if="showControls || !!slots.first" as-child>
|
||||
<slot name="first">
|
||||
<UButton :color="color" :variant="variant" :size="size" :icon="firstIcon || appConfig.ui.icons.chevronDoubleLeft" :to="to?.(1)" />
|
||||
@@ -153,7 +153,7 @@ const ui = computed(() => tv({ extend: pagination, slots: props.ui })())
|
||||
|
||||
<PaginationEllipsis v-else :key="item.type" :index="index" as-child>
|
||||
<slot name="ellipsis">
|
||||
<UButton :color="color" :variant="variant" :size="size" :icon="ellipsisIcon || appConfig.ui.icons.ellipsis" :class="ui.ellipsis()" />
|
||||
<UButton :color="color" :variant="variant" :size="size" :icon="ellipsisIcon || appConfig.ui.icons.ellipsis" :class="ui.ellipsis({ class: props.ui?.ellipsis })" />
|
||||
</slot>
|
||||
</PaginationEllipsis>
|
||||
</template>
|
||||
|
||||
@@ -63,7 +63,10 @@ const rootProps = useForwardPropsEmits(pick, emits)
|
||||
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8 }) as PopoverContentProps)
|
||||
const arrowProps = toRef(() => props.arrow as PopoverArrowProps)
|
||||
|
||||
const ui = computed(() => tv({ extend: popover, slots: props.ui })({ side: contentProps.value.side }))
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = computed(() => popover({
|
||||
side: contentProps.value.side
|
||||
}))
|
||||
|
||||
const Component = computed(() => props.mode === 'hover' ? HoverCard : Popover)
|
||||
</script>
|
||||
@@ -78,7 +81,7 @@ const Component = computed(() => props.mode === 'hover' ? HoverCard : Popover)
|
||||
<Component.Content v-bind="contentProps" :class="ui.content({ class: props.class })">
|
||||
<slot name="content" />
|
||||
|
||||
<Component.Arrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow()" />
|
||||
<Component.Arrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
|
||||
</Component.Content>
|
||||
</Component.Portal>
|
||||
</Component.Root>
|
||||
|
||||
@@ -129,7 +129,7 @@ function stepVariant(index: number | string) {
|
||||
return 'other'
|
||||
}
|
||||
|
||||
const ui = computed(() => tv({ extend: progress, slots: props.ui })({
|
||||
const ui = computed(() => progress({
|
||||
animation: props.animation,
|
||||
size: props.size,
|
||||
color: props.color,
|
||||
@@ -140,18 +140,18 @@ const ui = computed(() => tv({ extend: progress, slots: props.ui })({
|
||||
|
||||
<template>
|
||||
<div :class="ui.root({ class: props.class })">
|
||||
<div v-if="!isIndeterminate && (status || $slots.status)" :class="ui.status()" :style="statusStyle">
|
||||
<div v-if="!isIndeterminate && (status || $slots.status)" :class="ui.status({ class: props.ui?.status })" :style="statusStyle">
|
||||
<slot name="status" :percent="percent">
|
||||
{{ percent }}%
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<ProgressRoot v-bind="rootProps" :max="realMax" :class="ui.base()" style="transform: translateZ(0)">
|
||||
<ProgressIndicator :class="ui.indicator()" :style="indicatorStyle" />
|
||||
<ProgressRoot v-bind="rootProps" :max="realMax" :class="ui.base({ class: props.ui?.base })" style="transform: translateZ(0)">
|
||||
<ProgressIndicator :class="ui.indicator({ class: props.ui?.indicator })" :style="indicatorStyle" />
|
||||
</ProgressRoot>
|
||||
|
||||
<div v-if="hasSteps" :class="ui.steps()">
|
||||
<div v-for="(step, index) in max" :key="index" :class="ui.step({ step: stepVariant(index) })">
|
||||
<div v-if="hasSteps" :class="ui.steps({ class: props.ui?.steps })">
|
||||
<div v-for="(step, index) in max" :key="index" :class="ui.step({ class: props.ui?.step, step: stepVariant(index) })">
|
||||
<slot :name="`step-${index}`" :step="step">
|
||||
{{ step }}
|
||||
</slot>
|
||||
|
||||
@@ -50,7 +50,7 @@ export interface RadioGroupSlots<T> {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends RadioGroupItem | AcceptableValue">
|
||||
import { ref, computed } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { RadioGroupRoot, RadioGroupItem, RadioGroupIndicator, Label, useForwardPropsEmits } from 'radix-vue'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
import { useId, useFormField } from '#imports'
|
||||
@@ -66,7 +66,7 @@ const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', '
|
||||
const { emitFormChange, emitFormInput, color, name, size, id: _id, disabled } = useFormField<RadioGroupProps<T>>(props)
|
||||
const id = _id.value ?? useId()
|
||||
|
||||
const ui = computed(() => tv({ extend: radioGroup, slots: props.ui })({
|
||||
const ui = computed(() => radioGroup({
|
||||
size: size.value,
|
||||
color: color.value,
|
||||
disabled: disabled.value,
|
||||
@@ -113,29 +113,29 @@ function onUpdate(value: any) {
|
||||
:class="ui.root({ class: props.class })"
|
||||
@update:model-value="onUpdate"
|
||||
>
|
||||
<fieldset :class="ui.fieldset()">
|
||||
<legend v-if="legend || !!slots.legend" :class="ui.legend()">
|
||||
<fieldset :class="ui.fieldset({ class: props.ui?.fieldset })">
|
||||
<legend v-if="legend || !!slots.legend" :class="ui.legend({ class: props.ui?.legend })">
|
||||
<slot name="legend">
|
||||
{{ legend }}
|
||||
</slot>
|
||||
</legend>
|
||||
<div v-for="item in normalizedItems" :key="item.value" :class="ui.item()">
|
||||
<div :class="ui.container()">
|
||||
<div v-for="item in normalizedItems" :key="item.value" :class="ui.item({ class: props.ui?.item })">
|
||||
<div :class="ui.container({ class: props.ui?.container })">
|
||||
<RadioGroupItem
|
||||
:id="item.id"
|
||||
:value="item.value"
|
||||
:disabled="disabled"
|
||||
:class="ui.base()"
|
||||
:class="ui.base({ class: props.ui?.base })"
|
||||
>
|
||||
<RadioGroupIndicator :class="ui.indicator()" />
|
||||
<RadioGroupIndicator :class="ui.indicator({ class: props.ui?.indicator })" />
|
||||
</RadioGroupItem>
|
||||
</div>
|
||||
|
||||
<div :class="ui.wrapper()">
|
||||
<Label :class="ui.label()" :for="item.id">
|
||||
<div :class="ui.wrapper({ class: props.ui?.wrapper })">
|
||||
<Label :class="ui.label({ class: props.ui?.label })" :for="item.id">
|
||||
<slot name="label" :item="item" :model-value="modelValue">{{ item.label }}</slot>
|
||||
</Label>
|
||||
<p v-if="item.description || !!slots.description" :class="ui.description()">
|
||||
<p v-if="item.description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description" :item="item" :model-value="modelValue">
|
||||
{{ item.description }}
|
||||
</slot>
|
||||
|
||||
@@ -105,7 +105,7 @@ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponen
|
||||
|
||||
const selectSize = computed(() => buttonGroupSize.value || formGroupSize.value)
|
||||
|
||||
const ui = computed(() => tv({ extend: select, slots: props.ui })({
|
||||
const ui = computed(() => select({
|
||||
color: color.value,
|
||||
variant: props.variant,
|
||||
size: selectSize?.value,
|
||||
@@ -148,56 +148,56 @@ function onUpdateOpen(value: boolean) {
|
||||
@update:open="onUpdateOpen"
|
||||
>
|
||||
<SelectTrigger :class="ui.base({ class: props.class })">
|
||||
<span v-if="isLeading || !!slots.leading" :class="ui.leading()">
|
||||
<span v-if="isLeading || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
||||
<slot name="leading" :model-value="modelValue" :open="open" :ui="ui">
|
||||
<UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon()" />
|
||||
<UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<SelectValue :placeholder="placeholder ?? ' '" :class="ui.value()" />
|
||||
<SelectValue :placeholder="placeholder ?? ' '" :class="ui.value({ class: props.ui?.value })" />
|
||||
|
||||
<span v-if="isTrailing || !!slots.trailing" :class="ui.trailing()">
|
||||
<span v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })">
|
||||
<slot name="trailing" :model-value="modelValue" :open="open" :ui="ui">
|
||||
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon()" />
|
||||
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
|
||||
</slot>
|
||||
</span>
|
||||
</SelectTrigger>
|
||||
|
||||
<SelectPortal :disabled="!portal">
|
||||
<SelectContent :class="ui.content()" v-bind="contentProps">
|
||||
<SelectViewport :class="ui.viewport()">
|
||||
<SelectGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group()">
|
||||
<SelectContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
|
||||
<SelectViewport :class="ui.viewport({ class: props.ui?.viewport })">
|
||||
<SelectGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
|
||||
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
|
||||
<SelectLabel v-if="item?.type === 'label'" :class="ui.label()">
|
||||
<SelectLabel v-if="item?.type === 'label'" :class="ui.label({ class: props.ui?.label })">
|
||||
{{ item.label }}
|
||||
</SelectLabel>
|
||||
<SelectSeparator v-else-if="item?.type === 'separator'" :class="ui.separator()" />
|
||||
<SelectItem v-else :class="ui.item()" :disabled="item.disabled" :value="typeof item === 'object' ? item.value : item">
|
||||
<SelectSeparator v-else-if="item?.type === 'separator'" :class="ui.separator({ class: props.ui?.separator })" />
|
||||
<SelectItem v-else :class="ui.item({ class: props.ui?.item })" :disabled="item.disabled" :value="typeof item === 'object' ? item.value : item">
|
||||
<slot name="item" :item="(item as T)" :index="index">
|
||||
<slot name="item-leading" :item="(item as T)" :index="index">
|
||||
<UAvatar v-if="item.avatar" :size="(ui.itemLeadingAvatarSize() as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar()" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon()" />
|
||||
<UAvatar v-if="item.avatar" :size="(ui.itemLeadingAvatarSize() as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: props.ui?.itemLeadingIcon })" />
|
||||
<UChip
|
||||
v-else-if="item.chip"
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
inset
|
||||
standalone
|
||||
v-bind="item.chip"
|
||||
:class="ui.itemLeadingChip()"
|
||||
:class="ui.itemLeadingChip({ class: props.ui?.itemLeadingChip })"
|
||||
/>
|
||||
</slot>
|
||||
|
||||
<SelectItemText :class="ui.itemLabel()">
|
||||
<SelectItemText :class="ui.itemLabel({ class: props.ui?.itemLabel })">
|
||||
<slot name="item-label" :item="(item as T)" :index="index">
|
||||
{{ typeof item === 'object' ? item.label : item }}
|
||||
</slot>
|
||||
</SelectItemText>
|
||||
|
||||
<span :class="ui.itemTrailing()">
|
||||
<span :class="ui.itemTrailing({ class: props.ui?.itemTrailing })">
|
||||
<slot name="item-trailing" :item="(item as T)" :index="index" />
|
||||
|
||||
<SelectItemIndicator as-child>
|
||||
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon()" />
|
||||
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: props.ui?.itemTrailingIcon })" />
|
||||
</SelectItemIndicator>
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
@@ -121,7 +121,7 @@ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponen
|
||||
|
||||
const selectSize = computed(() => buttonGroupSize.value || formGroupSize.value)
|
||||
|
||||
const ui = computed(() => tv({ extend: selectMenu, slots: props.ui })({
|
||||
const ui = computed(() => selectMenu({
|
||||
color: color.value,
|
||||
variant: props.variant,
|
||||
size: selectSize?.value,
|
||||
@@ -201,74 +201,74 @@ function onUpdateOpen(value: boolean) {
|
||||
>
|
||||
<ComboboxAnchor as-child>
|
||||
<ComboboxTrigger :class="ui.base({ class: props.class })" tabindex="0">
|
||||
<span v-if="isLeading || !!slots.leading" :class="ui.leading()">
|
||||
<span v-if="isLeading || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
||||
<slot name="leading" :model-value="(modelValue as T)" :open="open" :ui="ui">
|
||||
<UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon()" />
|
||||
<UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<slot :model-value="(modelValue as T)" :open="open">
|
||||
<span v-if="multiple ? !!modelValue?.length : !!modelValue" :class="ui.value()">
|
||||
<span v-if="multiple ? !!modelValue?.length : !!modelValue" :class="ui.value({ class: props.ui?.value })">
|
||||
{{ displayValue(modelValue as T, multiple) }}
|
||||
</span>
|
||||
<span v-else :class="ui.placeholder()">
|
||||
<span v-else :class="ui.placeholder({ class: props.ui?.placeholder })">
|
||||
{{ placeholder ?? ' ' }}
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
<span v-if="isTrailing || !!slots.trailing" :class="ui.trailing()">
|
||||
<span v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })">
|
||||
<slot name="trailing" :model-value="(modelValue as T)" :open="open" :ui="ui">
|
||||
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon()" />
|
||||
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
|
||||
</slot>
|
||||
</span>
|
||||
</ComboboxTrigger>
|
||||
</ComboboxAnchor>
|
||||
|
||||
<ComboboxPortal :disabled="!portal">
|
||||
<ComboboxContent :class="ui.content()" v-bind="contentProps">
|
||||
<ComboboxInput :placeholder="searchPlaceholder" :class="ui.input()" autofocus autocomplete="off" />
|
||||
<ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
|
||||
<ComboboxInput :placeholder="searchPlaceholder" :class="ui.input({ class: props.ui?.input })" autofocus autocomplete="off" />
|
||||
|
||||
<ComboboxEmpty :class="ui.empty()">
|
||||
<ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
|
||||
<slot name="empty" :search-term="searchTerm">
|
||||
{{ searchTerm ? `No results for ${searchTerm}` : 'No results' }}
|
||||
</slot>
|
||||
</ComboboxEmpty>
|
||||
|
||||
<ComboboxViewport :class="ui.viewport()">
|
||||
<ComboboxGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group()">
|
||||
<ComboboxViewport :class="ui.viewport({ class: props.ui?.viewport })">
|
||||
<ComboboxGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
|
||||
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
|
||||
<ComboboxLabel v-if="item?.type === 'label'" :class="ui.label()">
|
||||
<ComboboxLabel v-if="item?.type === 'label'" :class="ui.label({ class: props.ui?.label })">
|
||||
{{ item.label }}
|
||||
</ComboboxLabel>
|
||||
|
||||
<ComboboxSeparator v-else-if="item?.type === 'separator'" :class="ui.separator()" />
|
||||
<ComboboxSeparator v-else-if="item?.type === 'separator'" :class="ui.separator({ class: props.ui?.separator })" />
|
||||
|
||||
<ComboboxItem v-else :class="ui.item()" :disabled="item.disabled" :value="item">
|
||||
<ComboboxItem v-else :class="ui.item({ class: props.ui?.item })" :disabled="item.disabled" :value="item">
|
||||
<slot name="item" :item="(item as T)" :index="index">
|
||||
<slot name="item-leading" :item="(item as T)" :index="index">
|
||||
<UAvatar v-if="item.avatar" :size="(ui.itemLeadingAvatarSize() as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar()" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon()" />
|
||||
<UAvatar v-if="item.avatar" :size="(ui.itemLeadingAvatarSize() as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: props.ui?.itemLeadingIcon })" />
|
||||
<UChip
|
||||
v-else-if="item.chip"
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
inset
|
||||
standalone
|
||||
v-bind="item.chip"
|
||||
:class="ui.itemLeadingChip()"
|
||||
:class="ui.itemLeadingChip({ class: props.ui?.itemLeadingChip })"
|
||||
/>
|
||||
</slot>
|
||||
|
||||
<span :class="ui.itemLabel()">
|
||||
<span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
|
||||
<slot name="item-label" :item="(item as T)" :index="index">
|
||||
{{ displayValue(item as T) }}
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span :class="ui.itemTrailing()">
|
||||
<span :class="ui.itemTrailing({ class: props.ui?.itemTrailing })">
|
||||
<slot name="item-trailing" :item="(item as T)" :index="index" />
|
||||
|
||||
<ComboboxItemIndicator as-child>
|
||||
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon()" />
|
||||
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: props.ui?.itemTrailingIcon })" />
|
||||
</ComboboxItemIndicator>
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
@@ -54,7 +54,7 @@ const slots = defineSlots<SeparatorSlots>()
|
||||
|
||||
const rootProps = useForwardProps(reactivePick(props, 'as', 'decorative', 'orientation'))
|
||||
|
||||
const ui = computed(() => tv({ extend: separator, slots: props.ui })({
|
||||
const ui = computed(() => separator({
|
||||
color: props.color,
|
||||
orientation: props.orientation,
|
||||
size: props.size,
|
||||
@@ -64,18 +64,18 @@ const ui = computed(() => tv({ extend: separator, slots: props.ui })({
|
||||
|
||||
<template>
|
||||
<Separator v-bind="rootProps" :class="ui.root({ class: props.class })">
|
||||
<div :class="ui.border()" />
|
||||
<div :class="ui.border({ class: props.ui?.border })" />
|
||||
|
||||
<template v-if="label || icon || avatar || !!slots.default">
|
||||
<div :class="ui.container()">
|
||||
<div :class="ui.container({ class: props.ui?.container })">
|
||||
<slot>
|
||||
<span v-if="label" :class="ui.label()">{{ label }}</span>
|
||||
<UIcon v-else-if="icon" :name="icon" :class="ui.icon()" />
|
||||
<UAvatar v-else-if="avatar" size="2xs" v-bind="avatar" :class="ui.avatar()" />
|
||||
<span v-if="label" :class="ui.label({ class: props.ui?.label })">{{ label }}</span>
|
||||
<UIcon v-else-if="icon" :name="icon" :class="ui.icon({ class: props.ui?.icon })" />
|
||||
<UAvatar v-else-if="avatar" size="2xs" v-bind="avatar" :class="ui.avatar({ class: props.ui?.avatar })" />
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<div :class="ui.border()" />
|
||||
<div :class="ui.border({ class: props.ui?.border })" />
|
||||
</template>
|
||||
</Separator>
|
||||
</template>
|
||||
|
||||
@@ -58,7 +58,7 @@ export interface SlideoverSlots {
|
||||
header(props?: {}): any
|
||||
title(props?: {}): any
|
||||
description(props?: {}): any
|
||||
close(props: { class: string }): any
|
||||
close(props: { ui: any }): any
|
||||
body(props?: {}): any
|
||||
footer(props?: {}): any
|
||||
}
|
||||
@@ -96,7 +96,7 @@ const contentEvents = computed(() => {
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed(() => tv({ extend: slideover, slots: props.ui })({
|
||||
const ui = computed(() => slideover({
|
||||
transition: props.transition,
|
||||
side: props.side
|
||||
}))
|
||||
@@ -109,26 +109,26 @@ const ui = computed(() => tv({ extend: slideover, slots: props.ui })({
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogPortal :disabled="!portal">
|
||||
<DialogOverlay v-if="overlay" :class="ui.overlay()" />
|
||||
<DialogOverlay v-if="overlay" :class="ui.overlay({ class: props.ui?.overlay })" />
|
||||
|
||||
<DialogContent :data-side="side" :class="ui.content({ class: props.class })" v-bind="contentProps" v-on="contentEvents">
|
||||
<slot name="content">
|
||||
<div v-if="!!slots.header || (title || !!slots.title) || (description || !!slots.description) || (close || !!slots.close)" :class="ui.header()">
|
||||
<div v-if="!!slots.header || (title || !!slots.title) || (description || !!slots.description) || (close || !!slots.close)" :class="ui.header({ class: props.ui?.header })">
|
||||
<slot name="header">
|
||||
<DialogTitle v-if="title || !!slots.title" :class="ui.title()">
|
||||
<DialogTitle v-if="title || !!slots.title" :class="ui.title({ class: props.ui?.title })">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogDescription v-if="description || !!slots.description" :class="ui.description()">
|
||||
<DialogDescription v-if="description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
</DialogDescription>
|
||||
|
||||
<DialogClose as-child>
|
||||
<slot name="close" :class="ui.close()">
|
||||
<slot name="close" :ui="ui">
|
||||
<UButton
|
||||
v-if="close"
|
||||
:icon="closeIcon || appConfig.ui.icons.close"
|
||||
@@ -137,18 +137,18 @@ const ui = computed(() => tv({ extend: slideover, slots: props.ui })({
|
||||
variant="ghost"
|
||||
aria-label="Close"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close()"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
/>
|
||||
</slot>
|
||||
</DialogClose>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<div :class="ui.body()">
|
||||
<div :class="ui.body({ class: props.ui?.body })">
|
||||
<slot name="body" />
|
||||
</div>
|
||||
|
||||
<div v-if="!!slots.footer" :class="ui.footer()">
|
||||
<div v-if="!!slots.footer" :class="ui.footer({ class: props.ui?.footer })">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</slot>
|
||||
|
||||
@@ -76,7 +76,7 @@ const sliderValue = computed({
|
||||
|
||||
const thumbsCount = computed(() => sliderValue.value?.length ?? 1)
|
||||
|
||||
const ui = computed(() => tv({ extend: slider, slots: props.ui })({
|
||||
const ui = computed(() => slider({
|
||||
disabled: disabled.value,
|
||||
size: size.value,
|
||||
color: color.value,
|
||||
@@ -103,10 +103,10 @@ function onChange(value: any) {
|
||||
@update:model-value="emitFormInput()"
|
||||
@value-commit="onChange"
|
||||
>
|
||||
<SliderTrack :class="ui.track()">
|
||||
<SliderRange :class="ui.range()" />
|
||||
<SliderTrack :class="ui.track({ class: props.ui?.track })">
|
||||
<SliderRange :class="ui.range({ class: props.ui?.range })" />
|
||||
</SliderTrack>
|
||||
|
||||
<SliderThumb v-for="count in thumbsCount" :key="count" :class="ui.thumb()" />
|
||||
<SliderThumb v-for="count in thumbsCount" :key="count" :class="ui.thumb({ class: props.ui?.thumb })" />
|
||||
</SliderRoot>
|
||||
</template>
|
||||
|
||||
@@ -68,7 +68,7 @@ const rootProps = useForwardProps(reactivePick(props, 'as', 'required', 'value')
|
||||
const { id: _id, emitFormChange, emitFormInput, size, color, name, disabled } = useFormField<SwitchProps>(props)
|
||||
const id = _id.value ?? useId()
|
||||
|
||||
const ui = computed(() => tv({ extend: switchTv, slots: props.ui })({
|
||||
const ui = computed(() => switchTv({
|
||||
size: size.value,
|
||||
color: color.value,
|
||||
required: props.required,
|
||||
@@ -87,7 +87,7 @@ function onUpdate(value: any) {
|
||||
|
||||
<template>
|
||||
<div :class="ui.root({ class: props.class })">
|
||||
<div :class="ui.container()">
|
||||
<div :class="ui.container({ class: props.ui?.container })">
|
||||
<SwitchRoot
|
||||
:id="id"
|
||||
v-model:checked="modelValue"
|
||||
@@ -95,25 +95,25 @@ function onUpdate(value: any) {
|
||||
v-bind="rootProps"
|
||||
:name="name"
|
||||
:disabled="disabled || loading"
|
||||
:class="ui.base()"
|
||||
:class="ui.base({ class: props.ui?.base })"
|
||||
@update:checked="onUpdate"
|
||||
>
|
||||
<SwitchThumb :class="ui.thumb()">
|
||||
<UIcon v-if="loading" :name="loadingIcon || appConfig.ui.icons.loading" :class="ui.icon({ checked: true, unchecked: true })" />
|
||||
<SwitchThumb :class="ui.thumb({ class: props.ui?.thumb })">
|
||||
<UIcon v-if="loading" :name="loadingIcon || appConfig.ui.icons.loading" :class="ui.icon({ class: props.ui?.icon, checked: true, unchecked: true })" />
|
||||
<template v-else>
|
||||
<UIcon v-if="checkedIcon" :name="checkedIcon" :class="ui.icon({ checked: true })" />
|
||||
<UIcon v-if="uncheckedIcon" :name="uncheckedIcon" :class="ui.icon({ unchecked: true })" />
|
||||
<UIcon v-if="checkedIcon" :name="checkedIcon" :class="ui.icon({ class: props.ui?.icon, checked: true })" />
|
||||
<UIcon v-if="uncheckedIcon" :name="uncheckedIcon" :class="ui.icon({ class: props.ui?.icon, unchecked: true })" />
|
||||
</template>
|
||||
</SwitchThumb>
|
||||
</SwitchRoot>
|
||||
</div>
|
||||
<div v-if="(label || !!slots.label) || (description || !!slots.description)" :class="ui.wrapper()">
|
||||
<Label v-if="label || !!slots.label" :for="id" :class="ui.label()">
|
||||
<div v-if="(label || !!slots.label) || (description || !!slots.description)" :class="ui.wrapper({ class: props.ui?.wrapper })">
|
||||
<Label v-if="label || !!slots.label" :for="id" :class="ui.label({ class: props.ui?.label })">
|
||||
<slot name="label" :label="label">
|
||||
{{ label }}
|
||||
</slot>
|
||||
</Label>
|
||||
<p v-if="description || !!slots.description" :class="ui.description()">
|
||||
<p v-if="description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description" :description="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
|
||||
@@ -74,7 +74,7 @@ const slots = defineSlots<TabsSlots<T>>()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultValue', 'orientation', 'activationMode', 'modelValue'), emits)
|
||||
const contentProps = toRef(() => defu(props.content || {}, { forceMount: true }) as TabsContentProps)
|
||||
|
||||
const ui = computed(() => tv({ extend: tabs, slots: props.ui })({
|
||||
const ui = computed(() => tabs({
|
||||
color: props.color,
|
||||
variant: props.variant,
|
||||
size: props.size,
|
||||
@@ -84,16 +84,16 @@ const ui = computed(() => tv({ extend: tabs, slots: props.ui })({
|
||||
|
||||
<template>
|
||||
<TabsRoot v-bind="rootProps" :class="ui.root({ class: props.class })">
|
||||
<TabsList :class="ui.list()">
|
||||
<TabsIndicator :class="ui.indicator()" />
|
||||
<TabsList :class="ui.list({ class: props.ui?.list })">
|
||||
<TabsIndicator :class="ui.indicator({ class: props.ui?.indicator })" />
|
||||
|
||||
<TabsTrigger v-for="(item, index) of items" :key="index" :value="item.value || String(index)" :disabled="item.disabled" :class="ui.trigger()">
|
||||
<TabsTrigger v-for="(item, index) of items" :key="index" :value="item.value || String(index)" :disabled="item.disabled" :class="ui.trigger({ class: props.ui?.trigger })">
|
||||
<slot name="leading" :item="item" :index="index">
|
||||
<UAvatar v-if="item.avatar" :size="(ui.leadingAvatarSize() as any)" v-bind="item.avatar" :class="ui.leadingAvatar()" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.leadingIcon()" />
|
||||
<UAvatar v-if="item.avatar" :size="(ui.leadingAvatarSize() as any)" v-bind="item.avatar" :class="ui.leadingAvatar({ class: props.ui?.leadingAvatar })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
</slot>
|
||||
|
||||
<span v-if="item.label || !!slots.default" :class="ui.label()">
|
||||
<span v-if="item.label || !!slots.default" :class="ui.label({ class: props.ui?.label })">
|
||||
<slot :item="item" :index="index">{{ item.label }}</slot>
|
||||
</span>
|
||||
|
||||
@@ -102,7 +102,7 @@ const ui = computed(() => tv({ extend: tabs, slots: props.ui })({
|
||||
</TabsList>
|
||||
|
||||
<template v-if="!!content">
|
||||
<TabsContent v-for="(item, index) of items" :key="index" v-bind="contentProps" :value="item.value || String(index)" :class="ui.content()">
|
||||
<TabsContent v-for="(item, index) of items" :key="index" v-bind="contentProps" :value="item.value || String(index)" :class="ui.content({ class: props.ui?.content })">
|
||||
<slot :name="item.slot || 'content'" :item="item" :index="index">
|
||||
{{ item.content }}
|
||||
</slot>
|
||||
|
||||
@@ -59,7 +59,7 @@ const [modelValue, modelModifiers] = defineModel<string | number>()
|
||||
|
||||
const { emitFormBlur, emitFormInput, emitFormChange, size, color, id, name, disabled } = useFormField<TextareaProps>(props)
|
||||
|
||||
const ui = computed(() => tv({ extend: textarea, slots: props.ui })({
|
||||
const ui = computed(() => textarea({
|
||||
color: color.value,
|
||||
variant: props.variant,
|
||||
size: size?.value
|
||||
@@ -164,7 +164,7 @@ onMounted(() => {
|
||||
:name="name"
|
||||
:rows="rows"
|
||||
:placeholder="placeholder"
|
||||
:class="ui.base()"
|
||||
:class="ui.base({ class: props.ui?.base })"
|
||||
:disabled="disabled"
|
||||
:required="required"
|
||||
v-bind="$attrs"
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface ToastSlots {
|
||||
title(props?: {}): any
|
||||
description(props?: {}): any
|
||||
actions(props?: {}): any
|
||||
close(props: { class: string }): any
|
||||
close(props: { ui: any }): any
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -76,7 +76,9 @@ const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultOpen',
|
||||
const multiline = computed(() => !!props.title && !!props.description)
|
||||
const duration = computed(() => props.duration || toaster?.value.duration)
|
||||
|
||||
const ui = computed(() => tv({ extend: toast, slots: props.ui })({ color: props.color }))
|
||||
const ui = computed(() => toast({
|
||||
color: props.color
|
||||
}))
|
||||
|
||||
const el = ref()
|
||||
const height = ref(0)
|
||||
@@ -105,25 +107,25 @@ defineExpose({
|
||||
:style="{ '--height': height }"
|
||||
>
|
||||
<slot name="leading">
|
||||
<UAvatar v-if="avatar" size="2xl" v-bind="avatar" :class="ui.avatar()" />
|
||||
<UIcon v-else-if="icon" :name="icon" :class="ui.icon()" />
|
||||
<UAvatar v-if="avatar" size="2xl" v-bind="avatar" :class="ui.avatar({ class: props.ui?.avatar })" />
|
||||
<UIcon v-else-if="icon" :name="icon" :class="ui.icon({ class: props.ui?.icon })" />
|
||||
</slot>
|
||||
|
||||
<div :class="ui.wrapper()">
|
||||
<ToastTitle v-if="title || !!slots.title" :class="ui.title()">
|
||||
<div :class="ui.wrapper({ class: props.ui?.wrapper })">
|
||||
<ToastTitle v-if="title || !!slots.title" :class="ui.title({ class: props.ui?.title })">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</ToastTitle>
|
||||
<template v-if="description || !!slots.description">
|
||||
<ToastDescription :class="ui.description()">
|
||||
<ToastDescription :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
</ToastDescription>
|
||||
</template>
|
||||
|
||||
<div v-if="multiline && actions?.length" :class="ui.actions({ multiline: true })">
|
||||
<div v-if="multiline && actions?.length" :class="ui.actions({ class: props.ui?.actions, multiline: true })">
|
||||
<slot name="actions">
|
||||
<ToastAction v-for="(action, index) in actions" :key="index" :alt-text="action.label || 'Action'" as-child @click.stop>
|
||||
<UButton size="xs" :color="color" v-bind="action" />
|
||||
@@ -132,7 +134,7 @@ defineExpose({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="(!multiline && actions?.length) || close !== null" :class="ui.actions({ multiline: false })">
|
||||
<div v-if="(!multiline && actions?.length) || close !== null" :class="ui.actions({ class: props.ui?.actions, multiline: false })">
|
||||
<template v-if="!multiline">
|
||||
<slot name="actions">
|
||||
<ToastAction v-for="(action, index) in actions" :key="index" :alt-text="action.label || 'Action'" as-child @click.stop>
|
||||
@@ -142,7 +144,7 @@ defineExpose({
|
||||
</template>
|
||||
|
||||
<ToastClose as-child>
|
||||
<slot name="close" :class="ui.close()">
|
||||
<slot name="close" :ui="ui">
|
||||
<UButton
|
||||
v-if="close"
|
||||
:icon="closeIcon || appConfig.ui.icons.close"
|
||||
@@ -151,13 +153,13 @@ defineExpose({
|
||||
variant="link"
|
||||
aria-label="Close"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close()"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
@click.stop
|
||||
/>
|
||||
</slot>
|
||||
</ToastClose>
|
||||
</div>
|
||||
|
||||
<div v-if="remaining > 0 && duration" :class="ui.progress()" :style="{ width: `${remaining / duration * 100}%` }" />
|
||||
<div v-if="remaining > 0 && duration" :class="ui.progress({ class: props.ui?.progress })" :style="{ width: `${remaining / duration * 100}%` }" />
|
||||
</ToastRoot>
|
||||
</template>
|
||||
|
||||
@@ -66,7 +66,7 @@ const swipeDirection = computed(() => {
|
||||
return 'right'
|
||||
})
|
||||
|
||||
const ui = computed(() => tv({ extend: toaster, slots: props.ui })({
|
||||
const ui = computed(() => toaster({
|
||||
position: props.position,
|
||||
swipeDirection: swipeDirection.value
|
||||
}))
|
||||
|
||||
@@ -59,7 +59,10 @@ const rootProps = useForwardPropsEmits(reactivePick(props, 'defaultOpen', 'open'
|
||||
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8 }) as TooltipContentProps)
|
||||
const arrowProps = toRef(() => props.arrow as TooltipArrowProps)
|
||||
|
||||
const ui = computed(() => tv({ extend: tooltip, slots: props.ui })({ side: contentProps.value.side }))
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = computed(() => tooltip({
|
||||
side: contentProps.value.side
|
||||
}))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -71,14 +74,14 @@ const ui = computed(() => tv({ extend: tooltip, slots: props.ui })({ side: conte
|
||||
<TooltipPortal :disabled="!portal">
|
||||
<TooltipContent v-bind="contentProps" :class="ui.content({ class: props.class })">
|
||||
<slot name="content">
|
||||
<span v-if="text" :class="ui.text()">{{ text }}</span>
|
||||
<span v-if="text" :class="ui.text({ class: props.ui?.text })">{{ text }}</span>
|
||||
|
||||
<span v-if="kbds?.length" :class="ui.kbds()">
|
||||
<span v-if="kbds?.length" :class="ui.kbds({ class: props.ui?.kbds })">
|
||||
<UKbd v-for="(kbd, index) in kbds" :key="index" size="sm" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
<TooltipArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow()" />
|
||||
<TooltipArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</TooltipRoot>
|
||||
|
||||
@@ -65,6 +65,9 @@ export default (options: Required<ModuleOptions>) => ({
|
||||
},
|
||||
other: {
|
||||
step: 'opacity-0'
|
||||
},
|
||||
last: {
|
||||
step: ''
|
||||
}
|
||||
},
|
||||
orientation: {
|
||||
|
||||
@@ -120,11 +120,11 @@ exports[`Breadcrumb > renders with separatorIcon correctly 1`] = `
|
||||
exports[`Breadcrumb > renders with ui correctly 1`] = `
|
||||
"<div aria-label="breadcrumb" class="relative min-w-0">
|
||||
<ol class="flex items-center gap-1.5">
|
||||
<li class="flex min-w-0"><a href="/" class="group relative flex items-center gap-1.5 text-sm min-w-0 text-gray-500 dark:text-gray-400 font-medium hover:text-gray-700 dark:hover:text-gray-200 transition-colors"><span class="inline-flex items-center justify-center select-none overflow-hidden rounded-full align-middle bg-gray-100 dark:bg-gray-800 size-5 text-[10px] shrink-0"><img role="img" src="https://avatars.githubusercontent.com/u/739984?v=4" class="h-full w-full rounded-[inherit] object-cover" style="display: none;"><span class="font-medium leading-none text-gray-500 dark:text-gray-400 truncate"></span></span><span class="truncate">Home</span></a></li>
|
||||
<li class="flex min-w-0"><a href="/" class="group relative flex items-center gap-1.5 text-sm min-w-0 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-colors font-bold"><span class="inline-flex items-center justify-center select-none overflow-hidden rounded-full align-middle bg-gray-100 dark:bg-gray-800 size-5 text-[10px] shrink-0"><img role="img" src="https://avatars.githubusercontent.com/u/739984?v=4" class="h-full w-full rounded-[inherit] object-cover" style="display: none;"><span class="font-medium leading-none text-gray-500 dark:text-gray-400 truncate"></span></span><span class="truncate">Home</span></a></li>
|
||||
<li role="presentation" class="flex"><span class="iconify i-heroicons:chevron-right-20-solid shrink-0 size-5 text-gray-500 dark:text-gray-400" aria-hidden="true"></span></li>
|
||||
<li class="flex min-w-0"><span class="group relative flex items-center gap-1.5 text-sm min-w-0 text-gray-500 dark:text-gray-400 font-medium cursor-not-allowed opacity-75"><span class="iconify i-heroicons:square-3-stack-3d shrink-0 size-5" aria-hidden="true"></span><span class="truncate">Navigation</span></span></li>
|
||||
<li class="flex min-w-0"><span class="group relative flex items-center gap-1.5 text-sm min-w-0 text-gray-500 dark:text-gray-400 cursor-not-allowed opacity-75 font-bold"><span class="iconify i-heroicons:square-3-stack-3d shrink-0 size-5" aria-hidden="true"></span><span class="truncate">Navigation</span></span></li>
|
||||
<li role="presentation" class="flex"><span class="iconify i-heroicons:chevron-right-20-solid shrink-0 size-5 text-gray-500 dark:text-gray-400" aria-hidden="true"></span></li>
|
||||
<li class="flex min-w-0"><a href="/breadcrumb" class="group relative flex items-center gap-1.5 text-sm min-w-0 text-primary-500 dark:text-primary-400 font-semibold"><span class="iconify i-heroicons:link shrink-0 size-5" aria-hidden="true"></span><span class="truncate">Breadcrumb</span></a></li>
|
||||
<li class="flex min-w-0"><a href="/breadcrumb" class="group relative flex items-center gap-1.5 text-sm min-w-0 text-primary-500 dark:text-primary-400 font-bold"><span class="iconify i-heroicons:link shrink-0 size-5" aria-hidden="true"></span><span class="truncate">Breadcrumb</span></a></li>
|
||||
<!--v-if-->
|
||||
</ol>
|
||||
</div>"
|
||||
|
||||
@@ -50,7 +50,7 @@ exports[`Chip > renders with size xs correctly 1`] = `"<div class="relative inli
|
||||
|
||||
exports[`Chip > renders with text correctly 1`] = `"<div class="relative inline-flex items-center justify-center shrink-0"><span class="rounded-full ring ring-white dark:ring-gray-900 flex items-center justify-center text-white dark:text-gray-900 font-medium whitespace-nowrap bg-primary-500 dark:bg-primary-400 h-[8px] min-w-[8px] text-[8px] top-0 right-0 absolute -translate-y-1/2 translate-x-1/2 transform">Text</span></div>"`;
|
||||
|
||||
exports[`Chip > renders with ui correctly 1`] = `"<div class="relative inline-flex items-center justify-center shrink-0"><span class="rounded-full ring ring-white dark:ring-gray-900 flex items-center justify-center font-medium whitespace-nowrap text-gray-500 dark:text-gray-400 bg-primary-500 dark:bg-primary-400 h-[8px] min-w-[8px] text-[8px] top-0 right-0 absolute -translate-y-1/2 translate-x-1/2 transform"></span></div>"`;
|
||||
exports[`Chip > renders with ui correctly 1`] = `"<div class="relative inline-flex items-center justify-center shrink-0"><span class="rounded-full ring ring-white dark:ring-gray-900 flex items-center justify-center font-medium whitespace-nowrap bg-primary-500 dark:bg-primary-400 h-[8px] min-w-[8px] text-[8px] top-0 right-0 absolute -translate-y-1/2 translate-x-1/2 transform text-gray-500 dark:text-gray-400"></span></div>"`;
|
||||
|
||||
exports[`Chip > renders without show correctly 1`] = `
|
||||
"<div class="relative inline-flex items-center justify-center shrink-0">
|
||||
|
||||
@@ -855,7 +855,7 @@ exports[`DropdownMenu > renders with ui correctly 1`] = `
|
||||
|
||||
|
||||
<div data-radix-popper-content-wrapper="" style="position: fixed; left: 0px; top: 0px; transform: translate(0, -200%); min-width: max-content;">
|
||||
<div role="menu" aria-orientation="vertical" data-radix-menu-content="" data-state="open" dir="ltr" tabindex="-1" data-orientation="vertical" style="outline-color: none; outline-style: none; outline-width: initial; --radix-dropdown-menu-content-transform-origin: var(--radix-popper-transform-origin); --radix-dropdown-menu-content-available-width: var(--radix-popper-available-width); --radix-dropdown-menu-content-available-height: var(--radix-popper-available-height); --radix-dropdown-menu-trigger-width: var(--radix-popper-anchor-width); --radix-dropdown-menu-trigger-height: var(--radix-popper-anchor-height); animation: none;" data-dismissable-layer="" id="radix-vue-dropdown-menu-content-28" aria-labelledby="" class="min-w-32 bg-white dark:bg-gray-900 shadow-lg rounded-md ring ring-gray-200 dark:ring-gray-800 divide-y divide-gray-200 dark:divide-gray-800 overflow-y-auto scroll-py-1 data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in]" data-side="bottom" data-align="center">
|
||||
<div role="menu" aria-orientation="vertical" data-radix-menu-content="" data-state="open" dir="ltr" tabindex="-1" data-orientation="vertical" style="outline-color: none; outline-style: none; outline-width: initial; --radix-dropdown-menu-content-transform-origin: var(--radix-popper-transform-origin); --radix-dropdown-menu-content-available-width: var(--radix-popper-available-width); --radix-dropdown-menu-content-available-height: var(--radix-popper-available-height); --radix-dropdown-menu-trigger-width: var(--radix-popper-anchor-width); --radix-dropdown-menu-trigger-height: var(--radix-popper-anchor-height); animation: none;" data-dismissable-layer="" id="radix-vue-dropdown-menu-content-28" aria-labelledby="" class="min-w-32 bg-white dark:bg-gray-900 shadow-lg rounded-md ring ring-gray-200 dark:ring-gray-800 divide-y divide-gray-200 dark:divide-gray-800 overflow-y-auto scroll-py-1 data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in]" uioverride="[object Object]" data-side="bottom" data-align="center">
|
||||
<div role="group" class="p-1 isolate">
|
||||
<div class="w-full flex items-center font-semibold text-gray-900 dark:text-white p-1.5 text-sm gap-1.5"><span class="inline-flex items-center justify-center select-none overflow-hidden rounded-full align-middle bg-gray-100 dark:bg-gray-800 size-5 text-[10px] shrink-0"><img role="img" src="https://avatars.githubusercontent.com/u/739984?v=4" class="h-full w-full rounded-[inherit] object-cover" style="display: none;"><span class="font-medium leading-none text-gray-500 dark:text-gray-400 truncate"></span></span><span class="truncate">My account<!--v-if--></span>
|
||||
<!--v-if-->
|
||||
|
||||
@@ -181,7 +181,7 @@ exports[`Input > renders with type correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`Input > renders with ui correctly 1`] = `
|
||||
"<div class="relative inline-flex items-center"><input type="text" class="w-full border-0 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 rounded-full px-2.5 py-1.5 text-sm gap-1.5 shadow-sm bg-white dark:bg-gray-900 text-gray-900 dark:text-white ring ring-inset ring-gray-300 dark:ring-gray-700 focus-visible:ring-2 focus-visible:ring-primary-500 dark:focus-visible:ring-primary-400">
|
||||
"<div class="relative inline-flex items-center"><input type="text" class="w-full border-0 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 px-2.5 py-1.5 text-sm gap-1.5 shadow-sm bg-white dark:bg-gray-900 text-gray-900 dark:text-white ring ring-inset ring-gray-300 dark:ring-gray-700 focus-visible:ring-2 focus-visible:ring-primary-500 dark:focus-visible:ring-primary-400 rounded-full">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>"
|
||||
|
||||
@@ -262,7 +262,7 @@ exports[`Progress > renders with status slot correctly 1`] = `
|
||||
exports[`Progress > renders with ui correctly 1`] = `
|
||||
"<div class="gap-2 w-full flex flex-col">
|
||||
<!--v-if-->
|
||||
<div aria-valuemax="100" aria-valuemin="0" aria-valuetext="0%" aria-label="0%" role="progressbar" data-state="indeterminate" data-max="100" class="relative overflow-hidden rounded-full bg-white dark:bg-gray-900 w-full h-2" style="transform: translateZ(0);">
|
||||
<div aria-valuemax="100" aria-valuemin="0" aria-valuetext="0%" aria-label="0%" role="progressbar" data-state="indeterminate" data-max="100" class="relative overflow-hidden rounded-full w-full h-2 bg-white dark:bg-gray-900" style="transform: translateZ(0);">
|
||||
<div data-state="indeterminate" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary-500 dark:bg-primary-400 data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite]"></div>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
|
||||
@@ -111,7 +111,7 @@ exports[`Slider > renders with size xs correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`Slider > renders with ui correctly 1`] = `
|
||||
"<span data-slider-impl="" dir="ltr" data-orientation="horizontal" style="--radix-slider-thumb-transform: translateX(-50%);" class="relative flex items-center select-none touch-none w-full" aria-disabled="false"><span data-orientation="horizontal" class="relative overflow-hidden rounded-full grow bg-gray-100 dark:bg-gray-800 h-[8px]"><span data-orientation="horizontal" style="left: 0%; right: 100%;" class="absolute rounded-full bg-primary-500 dark:bg-primary-400 h-full"></span></span>
|
||||
"<span data-slider-impl="" dir="ltr" data-orientation="horizontal" style="--radix-slider-thumb-transform: translateX(-50%);" class="relative flex items-center select-none touch-none w-full" aria-disabled="false"><span data-orientation="horizontal" class="relative overflow-hidden rounded-full grow h-[8px] bg-gray-100 dark:bg-gray-800"><span data-orientation="horizontal" style="left: 0%; right: 100%;" class="absolute rounded-full bg-primary-500 dark:bg-primary-400 h-full"></span></span>
|
||||
<div class="rounded-full bg-white dark:bg-gray-900 ring-2 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 ring-primary-500 dark:ring-primary-400 focus-visible:outline-primary-500/50 dark:focus-visible:outline-primary-400/50 size-4" role="slider" data-radix-vue-collection-item="" tabindex="0" data-orientation="horizontal" aria-valuemin="0" aria-valuemax="100" aria-orientation="horizontal" style="transform: var(--radix-slider-thumb-transform); position: absolute; left: calc(0% + 0px);" aria-valuenow="0"></div></span>
|
||||
<!---->"
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user