Skip to content

Commit

Permalink
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
Browse files Browse the repository at this point in the history
  • Loading branch information
romhml committed Sep 13, 2024
2 parents c11a3ce + ce91b5d commit d20dc62
Show file tree
Hide file tree
Showing 73 changed files with 2,708 additions and 1,019 deletions.
16 changes: 9 additions & 7 deletions docs/app/components/content/ComponentCode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import * as theme from '#build/ui'
import { get, set } from '#ui/utils'
const props = defineProps<{
/** Override the slug taken from the route */
slug?: string
class?: any
/** List of props to ignore in selection */
ignore?: string[]
Expand All @@ -32,7 +34,7 @@ const props = defineProps<{
const route = useRoute()
const { $prettier } = useNuxtApp()
const camelName = camelCase(route.params.slug[route.params.slug.length - 1])
const camelName = camelCase(props.slug ?? route.params.slug?.[route.params.slug.length - 1] ?? '')
const name = `U${upperFirst(camelName)}`
const componentProps = reactive({ ...(props.props || {}) })
Expand All @@ -45,11 +47,11 @@ function setComponentProp(name: string, value: any) {
set(componentProps, name, value)
}
const componentTheme = theme[camelName]
const componentTheme = (theme as any)[camelName]
const meta = await fetchComponentMeta(name as any)
function mapKeys(obj, parentKey = '') {
return Object.entries(obj || {}).flatMap(([key, value]) => {
function mapKeys(obj: object, parentKey = ''): any {
return Object.entries(obj || {}).flatMap(([key, value]: [string, any]) => {
if (typeof value === 'object' && !Array.isArray(value)) {
return mapKeys(value, key)
}
Expand All @@ -63,11 +65,11 @@ function mapKeys(obj, parentKey = '') {
const options = computed(() => {
const keys = mapKeys(props.props || {})
return keys.map((key) => {
return keys.map((key: string) => {
const prop = meta?.meta?.props?.find((prop: any) => prop.name === key)
const propItems = get(props.items, key, [])
const items = propItems.length
? propItems.map(item => ({
? propItems.map((item: any) => ({
value: item,
label: item
}))
Expand Down Expand Up @@ -253,7 +255,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${JSON.stringif
<component :is="name" v-bind="componentProps" @update:model-value="!!componentProps.modelValue && setComponentProp('modelValue', $event)">
<template v-for="slot in Object.keys(slots || {})" :key="slot" #[slot]>
<ContentSlot :name="slot" unwrap="p">
{{ slots[slot] }}
{{ slots?.[slot] }}
</ContentSlot>
</template>
</component>
Expand Down
2 changes: 1 addition & 1 deletion docs/app/components/content/ComponentEmits.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { upperFirst, camelCase } from 'scule'
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] ?? '')
const name = `U${upperFirst(camelName)}`
const meta = await fetchComponentMeta(name as any)
Expand Down
58 changes: 54 additions & 4 deletions docs/app/components/content/ComponentExample.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,26 @@ const props = withDefaults(defineProps<{
* @defaultValue true
*/
preview?: boolean
/**
* Whether to show the source code
* @defaultValue true
*/
source?: boolean
/**
* A list of variable props to link to the component.
*/
options?: Array<{
name: string
label: string
items: any[]
default: any
multiple: boolean
}>
}>(), {
preview: true
preview: true,
source: true
})
const { $prettier } = useNuxtApp()
Expand Down Expand Up @@ -71,16 +89,48 @@ const { data: ast } = await useAsyncData(`component-example-${camelName}`, async
return parseMarkdown(formatted)
}, { watch: [code] })
const optionsValues = ref(props.options?.reduce((acc, option) => {
if (option.name) {
acc[option.name] = option.default
}
return acc
}, {}))
</script>

<template>
<div class="my-5">
<div v-if="preview">
<div class="flex border border-b-0 border-gray-300 dark:border-gray-700 relative p-4 rounded-t-md z-[1]" :class="[props.class]">
<component :is="camelName" v-bind="componentProps" />
<div class="border border-gray-300 dark:border-gray-700 relative z-[1]" :class="[props.class, { 'border-b-0 rounded-t-md': props.source, 'rounded-md': !props.source }]">
<div v-if="props.options?.length" class="flex gap-4 p-4 border-b border-gray-300 dark:border-gray-700">
<UFormField
v-for="option in props.options"
:key="option.name"
:label="option.label"
:name="option.name"
size="sm"
class="inline-flex ring ring-gray-300 dark:ring-gray-700 rounded"
:ui="{
wrapper: 'bg-gray-50 dark:bg-gray-800/50 rounded-l flex border-r border-gray-300 dark:border-gray-700',
label: 'text-gray-500 dark:text-gray-400 px-2 py-1.5',
container: 'mt-0'
}"
>
<USelectMenu
v-model="optionsValues[option.name]"
:items="option.items"
class="rounded rounded-l-none w-40"
multiple
:ui="{ itemLeadingChip: 'size-2' }"
/>
</UFormField>
</div>
<div class="p-4">
<component :is="camelName" v-bind="{ ...componentProps, ...optionsValues }" />
</div>
</div>
</div>

<MDCRenderer v-if="ast" :body="ast.body" :data="ast.data" class="[&_pre]:!rounded-t-none [&_div.my-5]:!mt-0" />
<MDCRenderer v-if="ast && props.source" :body="ast.body" :data="ast.data" class="[&_pre]:!rounded-t-none [&_div.my-5]:!mt-0" />
</div>
</template>
6 changes: 4 additions & 2 deletions docs/app/components/content/ComponentProps.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ const props = defineProps<{
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] ?? '')
const name = `U${upperFirst(camelName)}`
const componentTheme = theme[camelName]
const componentTheme = (theme as any)[camelName]
const meta = await fetchComponentMeta(name as any)
const metaProps: ComputedRef<ComponentMeta['props']> = computed(() => {
Expand Down Expand Up @@ -43,6 +43,8 @@ const metaProps: ComputedRef<ComponentMeta['props']> = computed(() => {
if (b.name === 'ui') {
return -1
}
return 0
})
})
</script>
Expand Down
8 changes: 4 additions & 4 deletions docs/app/components/content/ComponentPropsSchema.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const props = defineProps<{
ignore?: string[]
}>()
function getSchemaProps(schema: PropertyMeta['schema']) {
function getSchemaProps(schema: PropertyMeta['schema']): any {
if (!schema || typeof schema === 'string' || !schema.schema) {
return []
}
Expand All @@ -15,12 +15,12 @@ function getSchemaProps(schema: PropertyMeta['schema']) {
return Object.values(schema.schema).filter(prop => !props.ignore?.includes(prop.name))
}
return (Array.isArray(schema.schema) ? schema.schema : Object.values(schema.schema)).flatMap(getSchemaProps)
return (Array.isArray(schema.schema) ? schema.schema : Object.values(schema.schema)).flatMap(getSchemaProps as any)
}
const schemaProps = computed(() => {
return getSchemaProps(props.prop.schema).map((prop) => {
const defaultValue = prop.default ?? prop.tags?.find(tag => tag.name === 'defaultValue')?.text
return getSchemaProps(props.prop.schema).map((prop: any) => {
const defaultValue = prop.default ?? prop.tags?.find((tag: any) => tag.name === 'defaultValue')?.text
let description = prop.description
if (defaultValue) {
description = description ? `${description} Defaults to \`${defaultValue}\`{lang="ts-type"}.` : `Defaults to \`${defaultValue}\`{lang="ts-type"}.`
Expand Down
2 changes: 1 addition & 1 deletion docs/app/components/content/ComponentSlots.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { upperFirst, camelCase } from 'scule'
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] ?? '')
const name = `U${upperFirst(camelName)}`
const meta = await fetchComponentMeta(name as any)
Expand Down
6 changes: 3 additions & 3 deletions docs/app/components/content/ComponentTheme.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import * as theme from '#build/ui'
const route = useRoute()
const name = camelCase(route.params.slug[route.params.slug.length - 1])
const name = camelCase(route.params.slug?.[route.params.slug.length - 1] ?? '')
const strippedCompoundVariants = ref(false)
function stripCompoundVariants(component) {
function stripCompoundVariants(component: any) {
if (component.compoundVariants) {
component.compoundVariants = component.compoundVariants.filter((compoundVariant: any) => {
if (compoundVariant.color) {
Expand Down Expand Up @@ -38,7 +38,7 @@ function stripCompoundVariants(component) {
const component = computed(() => {
return {
ui: {
[name]: stripCompoundVariants(theme[name])
[name]: stripCompoundVariants((theme as any)[name])
}
}
})
Expand Down
11 changes: 4 additions & 7 deletions docs/app/components/content/examples/chip/ChipShowExample.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@
const statuses = ['online', 'away', 'busy', 'offline']
const status = ref(statuses[0])
const color = computed(() => ({
online: 'green',
away: 'amber',
busy: 'red',
offline: 'gray'
})[status.value] as any)
const color = computed(() => status.value ? { online: 'green', away: 'amber', busy: 'red', offline: 'gray' }[status.value] as any : 'online')
const show = computed(() => status.value !== 'offline')
// Note: This is for demonstration purposes only. Don't do this at home.
onMounted(() => {
setInterval(() => {
status.value = statuses[(statuses.indexOf(status.value) + 1) % statuses.length]
if (status.value) {
status.value = statuses[(statuses.indexOf(status.value) + 1) % statuses.length]
}
}, 1000)
})
</script>
Expand Down
37 changes: 37 additions & 0 deletions docs/app/components/content/examples/form/FormExampleBasic.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script setup lang="ts">
import type { FormError, FormSubmitEvent } from '#ui/types'
const state = reactive({
email: undefined,
password: undefined
})
const validate = (state: any): FormError[] => {
const errors = []
if (!state.email) errors.push({ name: 'email', message: 'Required' })
if (!state.password) errors.push({ name: 'password', message: 'Required' })
return errors
}
const toast = useToast()
async function onSubmit(event: FormSubmitEvent<any>) {
toast.add({ title: 'Success', description: 'The form has been submitted.', color: 'green' })
console.log(event.data)
}
</script>

<template>
<UForm :validate="validate" :state="state" class="space-y-4" @submit="onSubmit">
<UFormField label="Email" name="email">
<UInput v-model="state.email" />
</UFormField>

<UFormField label="Password" name="password">
<UInput v-model="state.password" type="password" />
</UFormField>

<UButton type="submit">
Submit
</UButton>
</UForm>
</template>
Loading

0 comments on commit d20dc62

Please sign in to comment.