mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-02-05 14:48:03 +01:00
docs(ComponentCode): add cast prop (#2773)
This commit is contained in:
@@ -3,9 +3,42 @@
|
|||||||
import json5 from 'json5'
|
import json5 from 'json5'
|
||||||
import { upperFirst, camelCase, kebabCase } from 'scule'
|
import { upperFirst, camelCase, kebabCase } from 'scule'
|
||||||
import { hash } from 'ohash'
|
import { hash } from 'ohash'
|
||||||
|
import { CalendarDate } from '@internationalized/date'
|
||||||
import * as theme from '#build/ui'
|
import * as theme from '#build/ui'
|
||||||
import { get, set } from '#ui/utils'
|
import { get, set } from '#ui/utils'
|
||||||
|
|
||||||
|
interface Cast {
|
||||||
|
get: (args: any) => any
|
||||||
|
template: (args: any) => string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CastDateValue = [number, number, number]
|
||||||
|
|
||||||
|
const castMap: Record<string, Cast> = {
|
||||||
|
'DateValue': {
|
||||||
|
get: (args: CastDateValue) => new CalendarDate(...args),
|
||||||
|
template: (value: CalendarDate) => {
|
||||||
|
return value ? `new CalendarDate(${value.year}, ${value.month}, ${value.day})` : 'null'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'DateValue[]': {
|
||||||
|
get: (args: CastDateValue[]) => args.map(date => new CalendarDate(...date)),
|
||||||
|
template: (value: CalendarDate[]) => {
|
||||||
|
return value ? `[${value.map(date => `new CalendarDate(${date.year}, ${date.month}, ${date.day})`).join(', ')}]` : '[]'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'DateRange': {
|
||||||
|
get: (args: { start: CastDateValue, end: CastDateValue }) => ({ start: new CalendarDate(...args.start), end: new CalendarDate(...args.end) }),
|
||||||
|
template: (value: { start: CalendarDate, end: CalendarDate }) => {
|
||||||
|
if (!value.start || !value.end) {
|
||||||
|
return `{ start: null, end: null }`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `{ start: new CalendarDate(${value.start.year}, ${value.start.month}, ${value.start.day}), end: new CalendarDate(${value.end.year}, ${value.end.month}, ${value.end.day}) }`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
/** Override the slug taken from the route */
|
/** Override the slug taken from the route */
|
||||||
slug?: string
|
slug?: string
|
||||||
@@ -18,6 +51,8 @@ const props = defineProps<{
|
|||||||
external?: string[]
|
external?: string[]
|
||||||
/** List of props to use with `v-model` */
|
/** List of props to use with `v-model` */
|
||||||
model?: string[]
|
model?: string[]
|
||||||
|
/** List of props to cast from code and selection */
|
||||||
|
cast?: { [key: string]: string }
|
||||||
/** List of items for each prop */
|
/** List of items for each prop */
|
||||||
items?: { [key: string]: string[] }
|
items?: { [key: string]: string[] }
|
||||||
props?: { [key: string]: any }
|
props?: { [key: string]: any }
|
||||||
@@ -45,7 +80,17 @@ const camelName = camelCase(props.slug ?? route.params.slug?.[route.params.slug.
|
|||||||
const name = `U${upperFirst(camelName)}`
|
const name = `U${upperFirst(camelName)}`
|
||||||
const component = defineAsyncComponent(() => import(`#ui/components/${upperFirst(camelName)}.vue`))
|
const component = defineAsyncComponent(() => import(`#ui/components/${upperFirst(camelName)}.vue`))
|
||||||
|
|
||||||
const componentProps = reactive({ ...(props.props || {}) })
|
const componentProps = reactive({
|
||||||
|
...Object.fromEntries(Object.entries(props.props || {}).map(([key, value]) => {
|
||||||
|
const cast = props.cast?.[key]
|
||||||
|
|
||||||
|
if (cast && !castMap[cast]) {
|
||||||
|
throw new Error(`Unknown cast: ${cast}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [key, cast ? castMap[cast]!.get(value) : value]
|
||||||
|
}))
|
||||||
|
})
|
||||||
const componentEvents = reactive({
|
const componentEvents = reactive({
|
||||||
...Object.fromEntries((props.model || []).map(key => [`onUpdate:${key}`, (e: any) => setComponentProp(key, e)])),
|
...Object.fromEntries((props.model || []).map(key => [`onUpdate:${key}`, (e: any) => setComponentProp(key, e)])),
|
||||||
...(componentProps.modelValue ? { [`onUpdate:modelValue`]: (e: any) => setComponentProp('modelValue', e) } : {})
|
...(componentProps.modelValue ? { [`onUpdate:modelValue`]: (e: any) => setComponentProp('modelValue', e) } : {})
|
||||||
@@ -93,12 +138,10 @@ const options = computed(() => {
|
|||||||
chip: key.toLowerCase().endsWith('color') ? { color: variant } : undefined
|
chip: key.toLowerCase().endsWith('color') ? { color: variant } : undefined
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// TODO: process "undefined | Date | DateRange", https://github.com/nuxt/ui/issues/2651
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: key,
|
name: key,
|
||||||
label: key,
|
label: key,
|
||||||
type: prop?.type,
|
type: props?.cast?.[key] ?? prop?.type,
|
||||||
items
|
items
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -119,7 +162,10 @@ const code = computed(() => {
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
`
|
`
|
||||||
for (const key of props.external) {
|
for (const key of props.external) {
|
||||||
code += `const ${key === 'modelValue' ? 'value' : key} = ref(${json5.stringify(componentProps[key], null, 2).replace(/,([ |\t\n]+[}|\]])/g, '$1')})
|
const cast = props.cast?.[key]
|
||||||
|
const value = cast ? castMap[cast]!.template(componentProps[key]) : json5.stringify(componentProps[key], null, 2).replace(/,([ |\t\n]+[}|\]])/g, '$1')
|
||||||
|
|
||||||
|
code += `const ${key === 'modelValue' ? 'value' : key} = ref(${value})
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
code += `<\/script>
|
code += `<\/script>
|
||||||
|
|||||||
@@ -21,10 +21,31 @@ Use the `v-model` directive to control the selected date.
|
|||||||
|
|
||||||
::component-code
|
::component-code
|
||||||
---
|
---
|
||||||
|
cast:
|
||||||
|
modelValue: DateValue
|
||||||
|
ignore:
|
||||||
|
- modelValue
|
||||||
|
external:
|
||||||
|
- modelValue
|
||||||
|
props:
|
||||||
|
modelValue: [2022, 2, 3]
|
||||||
---
|
---
|
||||||
::
|
::
|
||||||
|
|
||||||
<!-- TODO: Add example with default value -->
|
Use the `default-value` prop to set the initial value when you do not need to control its state.
|
||||||
|
|
||||||
|
::component-code
|
||||||
|
---
|
||||||
|
cast:
|
||||||
|
defaultValue: DateValue
|
||||||
|
ignore:
|
||||||
|
- defaultValue
|
||||||
|
external:
|
||||||
|
- defaultValue
|
||||||
|
props:
|
||||||
|
defaultValue: [2022, 2, 6]
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
### Multiple
|
### Multiple
|
||||||
|
|
||||||
@@ -32,10 +53,17 @@ Use the `multiple` prop to allow multiple selections.
|
|||||||
|
|
||||||
::component-code
|
::component-code
|
||||||
---
|
---
|
||||||
|
prettier: true
|
||||||
|
cast:
|
||||||
|
modelValue: DateValue[]
|
||||||
ignore:
|
ignore:
|
||||||
- multiple
|
- multiple
|
||||||
|
- modelValue
|
||||||
|
external:
|
||||||
|
- modelValue
|
||||||
props:
|
props:
|
||||||
multiple: true
|
multiple: true
|
||||||
|
modelValue: [[2022, 2, 4], [2022, 2, 6], [2022, 2, 8]]
|
||||||
---
|
---
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -45,10 +73,20 @@ Use the `range` prop to select a range of dates.
|
|||||||
|
|
||||||
::component-code
|
::component-code
|
||||||
---
|
---
|
||||||
|
prettier: true
|
||||||
|
cast:
|
||||||
|
modelValue: DateRange
|
||||||
ignore:
|
ignore:
|
||||||
- range
|
- range
|
||||||
|
- modelValue.start
|
||||||
|
- modelValue.end
|
||||||
|
external:
|
||||||
|
- modelValue
|
||||||
props:
|
props:
|
||||||
range: true
|
range: true
|
||||||
|
modelValue:
|
||||||
|
start: [2022, 2, 3]
|
||||||
|
end: [2022, 2, 20]
|
||||||
---
|
---
|
||||||
::
|
::
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user