mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-25 17:30:37 +01:00
docs: improve ComponentCode and ComponentProps
This commit is contained in:
@@ -3,6 +3,7 @@ import { upperFirst, camelCase } from 'scule'
|
|||||||
import * as theme from '#build/ui'
|
import * as theme from '#build/ui'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
ignore?: string[]
|
||||||
props?: { [key: string]: any }
|
props?: { [key: string]: any }
|
||||||
slots?: { [key: string]: any }
|
slots?: { [key: string]: any }
|
||||||
}>()
|
}>()
|
||||||
@@ -16,22 +17,24 @@ const name = `U${upperFirst(camelName)}`
|
|||||||
const componentProps = reactive({ ...(props.props || {}) })
|
const componentProps = reactive({ ...(props.props || {}) })
|
||||||
|
|
||||||
const componentTheme = theme[camelName]
|
const componentTheme = theme[camelName]
|
||||||
// const meta = await fetchComponentMeta(name as any)
|
const meta = await fetchComponentMeta(name as any)
|
||||||
|
|
||||||
const options = computed(() => Object.keys(props.props || {}).map((key) => {
|
const options = computed(() => Object.keys(props.props || {}).filter((key) => {
|
||||||
// const prop = meta?.meta?.props?.find((prop: any) => prop.name === key)
|
return !props.ignore?.includes(key)
|
||||||
const variants = componentTheme.variants?.[key]
|
}).map((key) => {
|
||||||
const items = variants
|
const prop = meta?.meta?.props?.find((prop: any) => prop.name === key)
|
||||||
? Object.keys(variants).map(variant => ({
|
const variants = Object.keys(componentTheme.variants?.[key] || {})
|
||||||
|
const items = prop?.type === 'boolean'
|
||||||
|
? [{ value: true, label: 'true' }, { value: false, label: 'false' }]
|
||||||
|
: variants.map(variant => ({
|
||||||
value: variant,
|
value: variant,
|
||||||
label: variant,
|
label: variant,
|
||||||
chip: key === 'color' ? { color: variant } : undefined
|
chip: key === 'color' ? { color: variant } : undefined
|
||||||
})).filter(variant => key === 'color' ? !['error'].includes(variant.value) : true)
|
})).filter(variant => key === 'color' ? !['error'].includes(variant.value) : true)
|
||||||
: []
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: key,
|
name: key,
|
||||||
label: camelCase(key),
|
label: key,
|
||||||
items
|
items
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@@ -41,7 +44,29 @@ const code = computed(() => {
|
|||||||
<template>
|
<template>
|
||||||
<${name}`
|
<${name}`
|
||||||
for (const [key, value] of Object.entries(componentProps)) {
|
for (const [key, value] of Object.entries(componentProps)) {
|
||||||
code += ` ${key}="${value}"`
|
if (value === undefined || value === null || value === '') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const prop = meta?.meta?.props?.find((prop: any) => prop.name === key)
|
||||||
|
|
||||||
|
if (typeof value === 'boolean') {
|
||||||
|
if (value && prop?.default === 'true') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (!value && !prop?.default) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
code += value ? ` ${key}` : ` :${key}="false"`
|
||||||
|
} else {
|
||||||
|
const propDefault = prop && (prop.default ?? prop.tags?.find(tag => tag.name === 'defaultValue')?.text ?? componentTheme?.defaultVariants?.[prop.name])
|
||||||
|
if (propDefault === value) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
code += ` ${key}="${value}"`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.slots) {
|
if (props.slots) {
|
||||||
@@ -80,10 +105,10 @@ const { data: ast } = await useAsyncData(`${name}-code-${JSON.stringify({ props:
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="options.length" class="flex items-center gap-3 border border-gray-300 dark:border-gray-700 border-b-0 relative rounded-t-md px-4 py-2.5">
|
<div v-if="options.length" class="flex items-center gap-2.5 border border-gray-300 dark:border-gray-700 border-b-0 relative rounded-t-md px-4 py-2.5">
|
||||||
<template v-for="option in options" :key="option.name">
|
<template v-for="option in options" :key="option.name">
|
||||||
<UFormField
|
<UFormField
|
||||||
:label="upperFirst(option.label)"
|
:label="option.label"
|
||||||
size="sm"
|
size="sm"
|
||||||
class="inline-flex ring ring-gray-300 dark:ring-gray-700 rounded"
|
class="inline-flex ring ring-gray-300 dark:ring-gray-700 rounded"
|
||||||
:ui="{
|
:ui="{
|
||||||
@@ -100,6 +125,9 @@ const { data: ast } = await useAsyncData(`${name}-code-${JSON.stringify({ props:
|
|||||||
color="gray"
|
color="gray"
|
||||||
variant="soft"
|
variant="soft"
|
||||||
class="rounded rounded-l-none"
|
class="rounded rounded-l-none"
|
||||||
|
:search="false"
|
||||||
|
:class="[option.name === 'color' && 'pl-6']"
|
||||||
|
:ui="{ itemLeadingChip: 'size-2' }"
|
||||||
>
|
>
|
||||||
<template v-if="option.name === 'color'" #leading="{ modelValue, ui }">
|
<template v-if="option.name === 'color'" #leading="{ modelValue, ui }">
|
||||||
<UChip
|
<UChip
|
||||||
@@ -108,7 +136,7 @@ const { data: ast } = await useAsyncData(`${name}-code-${JSON.stringify({ props:
|
|||||||
standalone
|
standalone
|
||||||
:color="(modelValue as any)"
|
:color="(modelValue as any)"
|
||||||
:size="ui.itemLeadingChipSize()"
|
:size="ui.itemLeadingChipSize()"
|
||||||
:class="ui.itemLeadingChip()"
|
class="size-2"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</USelectMenu>
|
</USelectMenu>
|
||||||
@@ -120,7 +148,9 @@ const { data: ast } = await useAsyncData(`${name}-code-${JSON.stringify({ props:
|
|||||||
<div class="flex border border-b-0 border-gray-300 dark:border-gray-700 relative p-4" :class="[!options.length && 'rounded-t-md']">
|
<div class="flex border border-b-0 border-gray-300 dark:border-gray-700 relative p-4" :class="[!options.length && 'rounded-t-md']">
|
||||||
<component :is="name" v-bind="componentProps">
|
<component :is="name" v-bind="componentProps">
|
||||||
<template v-for="slot in Object.keys(slots || {})" :key="slot" #[slot]>
|
<template v-for="slot in Object.keys(slots || {})" :key="slot" #[slot]>
|
||||||
<ContentSlot :name="slot" unwrap="p" />
|
<ContentSlot :name="slot" unwrap="p">
|
||||||
|
{{ slots[slot] }}
|
||||||
|
</ContentSlot>
|
||||||
</template>
|
</template>
|
||||||
</component>
|
</component>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import { upperFirst, camelCase } from 'scule'
|
|||||||
import type { ComponentMeta } from 'vue-component-meta'
|
import type { ComponentMeta } from 'vue-component-meta'
|
||||||
import * as theme from '#build/ui'
|
import * as theme from '#build/ui'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
ignore?: string[]
|
||||||
|
}>()
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const camelName = camelCase(route.params.slug[route.params.slug.length - 1])
|
const camelName = camelCase(route.params.slug[route.params.slug.length - 1])
|
||||||
@@ -16,7 +20,9 @@ const metaProps: ComputedRef<ComponentMeta['props']> = computed(() => {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
return meta.meta.props.map((prop) => {
|
return meta.meta.props.filter((prop) => {
|
||||||
|
return !props.ignore?.includes(prop.name)
|
||||||
|
}).map((prop) => {
|
||||||
prop.default = prop.default ?? prop.tags?.find(tag => tag.name === 'defaultValue')?.text ?? componentTheme?.defaultVariants?.[prop.name]
|
prop.default = prop.default ?? prop.tags?.find(tag => tag.name === 'defaultValue')?.text ?? componentTheme?.defaultVariants?.[prop.name]
|
||||||
return prop
|
return prop
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user