feat(module): devtools integration (#2196)

Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
Romain Hamel
2024-11-05 22:17:56 +01:00
committed by GitHub
parent 7fc6b387b3
commit 701c75a2a8
100 changed files with 2062 additions and 59 deletions

View File

@@ -0,0 +1,76 @@
<script lang="ts">
import { z } from 'zod'
export const arrayInputSchema = z.object({
kind: z.literal('array'),
schema: z.array(z.any({}))
.or(z.record(z.number(), z.any({})).transform(t => Object.values(t)))
.transform((t) => {
return t.filter(s => s !== 'undefined')
}).pipe(z.array(z.any()).max(1))
})
export type ArrayInputSchema = z.infer<typeof arrayInputSchema>
</script>
<script setup lang="ts">
const props = defineProps<{
schema: ArrayInputSchema
}>()
const modelValue = defineModel<Array<any>>({})
const itemSchema = computed(() => {
return props.schema?.schema[0]
})
function removeArrayItem(index: number) {
if (!modelValue.value) return
modelValue.value.splice(index, 1)
}
function addArrayItem() {
if (!modelValue.value) {
modelValue.value = [{}]
} else {
modelValue.value.push({})
}
}
</script>
<template>
<div>
<div v-for="value, index in modelValue" :key="index" class="relative">
<ComponentPropInput
:model-value="value"
:meta="{ schema: itemSchema }"
/>
<UPopover>
<UButton variant="ghost" color="neutral" icon="i-heroicons-ellipsis-vertical" class="absolute top-4 right-1" />
<template #content>
<UButton
variant="ghost"
color="error"
icon="i-heroicons-trash"
block
@click="removeArrayItem(index)"
>
Remove
</UButton>
</template>
</UPopover>
</div>
<UButton
icon="i-heroicons-plus"
color="neutral"
variant="ghost"
block
class="justify-center mt-4"
@click="addArrayItem()"
>
Add value
</UButton>
</div>
</template>

View File

@@ -0,0 +1,20 @@
<script lang="ts">
import { z } from 'zod'
export const booleanInputSchema = z.literal('boolean').or(z.object({
kind: z.literal('enum'),
type: z.string().refine((type) => {
return type.split('|').some(t => t.trim() === 'boolean')
})
}))
export type BooleanInputSchema = z.infer<typeof booleanInputSchema>
</script>
<script setup lang="ts">
defineProps<{ schema: BooleanInputSchema }>()
</script>
<template>
<USwitch />
</template>

View File

@@ -0,0 +1,15 @@
<script lang="ts">
import { z } from 'zod'
export const numberInputSchema = z.literal('number')
export type NumberInputSchema = z.infer<typeof numberInputSchema>
</script>
<script setup lang="ts">
defineProps<{ schema: NumberInputSchema }>()
const modelValue = defineModel<number>()
</script>
<template>
<UInput v-model.number="modelValue" type="number" />
</template>

View File

@@ -0,0 +1,38 @@
<script lang="ts">
import { z } from 'zod'
export const objectInputSchema = z.object({
kind: z.literal('object'),
schema: z.record(z.string(), z.any())
})
export type ObjectInputSchema = z.infer<typeof objectInputSchema>
</script>
<script setup lang="ts">
const props = defineProps<{
schema: ObjectInputSchema
}>()
const modelValue = defineModel<Record<string, any>>({})
const attributesSchemas = computed(() => {
return Object.values(props.schema.schema)
})
</script>
<template>
<CollapseContainer>
<ComponentPropInput
v-for="attributeSchema in attributesSchemas"
:key="attributeSchema.name"
class="border-b last:border-b-0 border-[var(--ui-border)] p-4"
:model-value="modelValue?.[attributeSchema.name]"
:meta="attributeSchema"
@update:model-value="(value: any) => {
if (!modelValue) modelValue ||= {}
else modelValue[attributeSchema.name] = value
}"
/>
</CollapseContainer>
</template>

View File

@@ -0,0 +1,60 @@
<script lang="ts">
import { z } from 'zod'
export const stringEnumInputSchema = z.object({
kind: z.literal('enum'),
schema: z.array(z.string())
.or(z.record(z.any(), z.string()).transform<string[]>(t => Object.values(t)))
.transform<string[]>(t => t.filter(s => s.trim().match(/^["'`]/)).map(s => s.trim().replaceAll(/["'`]/g, '')))
.pipe(z.array(z.string()).min(1))
})
export type StringEnumInputSchema = z.infer<typeof stringEnumInputSchema>
</script>
<script setup lang="ts">
const props = defineProps<{
schema: StringEnumInputSchema
}>()
const sizes = ['xs', 'sm', 'md', 'lg', 'xl']
function parseSize(size: string) {
const sizePattern = sizes.join('|')
const regex = new RegExp(`^(\\d*)(${sizePattern})$`, 'i')
const match = size.match(regex)
if (!match) return null
const number = match[1] ? Number.parseInt(match[1], 10) : 1 // Default to 1 if no number is present
const suffix = match[2] ?? ''
return { number, suffix }
}
const options = computed(() => {
return [...props.schema.schema].sort((a, b) => {
const sizeA = parseSize(a)
const sizeB = parseSize(b)
if (!sizeA || !sizeB) return a.localeCompare(b)
const suffixAIndex = sizes.indexOf(sizeA.suffix)
const suffixBIndex = sizes.indexOf(sizeB.suffix)
if (suffixAIndex !== -1 && suffixBIndex !== -1) {
if (suffixAIndex !== suffixBIndex) {
return suffixAIndex - suffixBIndex
}
} else if (suffixAIndex === -1 || suffixBIndex === -1) {
if (sizeA.suffix !== sizeB.suffix) {
return sizeA.suffix.localeCompare(sizeB.suffix)
}
}
return sizeA.number - sizeB.number
})
})
</script>
<template>
<USelectMenu :items="options" class="min-w-[167px]" />
</template>

View File

@@ -0,0 +1,15 @@
<script lang="ts">
import { z } from 'zod'
export const stringInputSchema = z.literal('string').or(z.string().transform(t => t.split('|').find(s => s.trim() === 'string')).pipe(z.string()))
export type StringInputSchema = z.infer<typeof stringInputSchema>
</script>
<script setup lang="ts">
defineProps<{ schema: StringInputSchema }>()
</script>
<template>
<UInput />
</template>