fix(CheckboxGroup): proxy slots & ui prop

This commit is contained in:
Benjamin Canac
2025-04-24 12:26:48 +02:00
parent 6e27304d8c
commit bc06185282
5 changed files with 38 additions and 30 deletions

View File

@@ -50,14 +50,14 @@ export interface CheckboxGroupProps<T extends CheckboxGroupItem = CheckboxGroupI
*/
orientation?: CheckboxGroupRootProps['orientation']
class?: any
ui?: CheckboxGroup['slots']
ui?: CheckboxGroup['slots'] & CheckboxProps['ui']
}
export type CheckboxGroupEmits = CheckboxGroupRootEmits & {
change: [payload: Event]
}
type SlotProps<T extends CheckboxGroupItem> = (props: { item: T & { id: string }, modelValue?: CheckboxGroupValue }) => any
type SlotProps<T extends CheckboxGroupItem> = (props: { item: T & { id: string } }) => any
export interface CheckboxGroupSlots<T extends CheckboxGroupItem = CheckboxGroupItem> {
legend(props?: {}): any
@@ -72,7 +72,7 @@ import { CheckboxGroupRoot, useForwardProps, useForwardPropsEmits } from 'reka-u
import { reactivePick } from '@vueuse/core'
import { useAppConfig } from '#imports'
import { useFormField } from '../composables/useFormField'
import { get } from '../utils'
import { get, omit } from '../utils'
import { tv } from '../utils/tv'
const props = withDefaults(defineProps<CheckboxGroupProps<T>>(), {
@@ -88,6 +88,7 @@ const appConfig = useAppConfig() as CheckboxGroup['AppConfig']
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'orientation', 'loop', 'required'), emits)
const checkboxProps = useForwardProps(reactivePick(props, 'variant', 'indicator', 'icon'))
const proxySlots = omit(slots, ['legend'])
const { emitFormChange, emitFormInput, color, name, size, id: _id, disabled, ariaAttrs } = useFormField<CheckboxGroupProps<T>>(props, { bind: false })
const id = _id.value ?? useId()
@@ -169,7 +170,13 @@ function onUpdate(value: any) {
:size="size"
:name="name"
:disabled="item.disabled || disabled"
/>
:ui="props.ui ? omit(props.ui, ['root']) : undefined"
:class="ui.item({ class: props.ui?.item })"
>
<template v-for="(_, name) in proxySlots" #[name]>
<slot :name="(name as keyof CheckboxGroupSlots<T>)" :item="item" />
</template>
</UCheckbox>
</fieldset>
</CheckboxGroupRoot>
</template>

View File

@@ -2,7 +2,8 @@ export default {
slots: {
root: 'relative',
fieldset: 'flex gap-x-2',
legend: 'mb-1 block font-medium text-default'
legend: 'mb-1 block font-medium text-default',
item: ''
},
variants: {
orientation: {

View File

@@ -38,11 +38,11 @@ describe('CheckboxGroup', () => {
['with ariaLabel', { props, attrs: { 'aria-label': 'Aria label' } }],
['with as', { props: { ...props, as: 'section' } }],
['with class', { props: { ...props, class: 'absolute' } }],
['with ui', { props: { ...props, ui: { wrapper: 'ms-4' } } }],
['with ui', { props: { ...props, ui: { fieldset: 'gap-x-4', label: 'text-red' } } }],
// Slots
['with legend slot', { props, slots: { label: () => 'Legend slot' } }],
['with legend slot', { props, slots: { legend: () => 'Legend slot' } }],
['with label slot', { props, slots: { label: () => 'Label slot' } }],
['with description slot', { props, slots: { label: () => 'Description slot' } }]
['with description slot', { props, slots: { description: () => 'Description slot' } }]
])('renders %s correctly', async (nameOrHtml: string, options: { props?: CheckboxGroupProps, slots?: Partial<CheckboxGroupSlots> }) => {
const html = await ComponentRender(nameOrHtml, options, CheckboxGroup)
expect(html).toMatchSnapshot()

View File

@@ -189,7 +189,7 @@ exports[`CheckboxGroup > renders with description slot correctly 1`] = `
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0:1" class="block font-medium text-default">Option 1</p>
<!--v-if-->
<p class="text-muted">Description slot</p>
</div>
</label><label class="relative flex items-start flex-row">
<div class="flex items-center h-5"><button tabindex="-1" data-orientation="vertical" class="rounded-sm ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary size-4" id="v-0:2" role="checkbox" type="button" aria-checked="false" aria-required="false" data-state="unchecked" data-reka-collection-item="">
@@ -198,7 +198,7 @@ exports[`CheckboxGroup > renders with description slot correctly 1`] = `
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0:2" class="block font-medium text-default">Option 2</p>
<!--v-if-->
<p class="text-muted">Description slot</p>
</div>
</label><label class="relative flex items-start flex-row">
<div class="flex items-center h-5"><button tabindex="-1" data-orientation="vertical" class="rounded-sm ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary size-4" id="v-0:3" role="checkbox" type="button" aria-checked="false" aria-required="false" data-state="unchecked" data-reka-collection-item="">
@@ -207,7 +207,7 @@ exports[`CheckboxGroup > renders with description slot correctly 1`] = `
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0:3" class="block font-medium text-default">Option 3</p>
<!--v-if-->
<p class="text-muted">Description slot</p>
</div>
</label>
</fieldset>
@@ -507,7 +507,7 @@ exports[`CheckboxGroup > renders with label slot correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0:1" class="block font-medium text-default">Option 1</p>
<p for="v-0:1" class="block font-medium text-default">Label slot</p>
<!--v-if-->
</div>
</label><label class="relative flex items-start flex-row">
@@ -516,7 +516,7 @@ exports[`CheckboxGroup > renders with label slot correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0:2" class="block font-medium text-default">Option 2</p>
<p for="v-0:2" class="block font-medium text-default">Label slot</p>
<!--v-if-->
</div>
</label><label class="relative flex items-start flex-row">
@@ -525,7 +525,7 @@ exports[`CheckboxGroup > renders with label slot correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0:3" class="block font-medium text-default">Option 3</p>
<p for="v-0:3" class="block font-medium text-default">Label slot</p>
<!--v-if-->
</div>
</label>
@@ -573,7 +573,7 @@ exports[`CheckboxGroup > renders with labelKey correctly 1`] = `
exports[`CheckboxGroup > renders with legend slot correctly 1`] = `
"<div tabindex="0" data-orientation="vertical" dir="ltr" style="outline-color: none; outline-style: none; outline-width: initial;" id="v-0" class="relative">
<fieldset class="flex gap-x-2 flex-col gap-y-1">
<!--v-if--><label class="relative flex items-start flex-row">
<legend class="mb-1 block font-medium text-default text-sm">Legend slot</legend><label class="relative flex items-start flex-row">
<div class="flex items-center h-5"><button tabindex="-1" data-orientation="vertical" class="rounded-sm ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary size-4" id="v-0:1" role="checkbox" type="button" aria-checked="false" aria-required="false" data-state="unchecked" data-reka-collection-item="">
<!---->
<!---->
@@ -994,14 +994,14 @@ exports[`CheckboxGroup > renders with size xs correctly 1`] = `
exports[`CheckboxGroup > renders with ui correctly 1`] = `
"<div tabindex="0" data-orientation="vertical" dir="ltr" style="outline-color: none; outline-style: none; outline-width: initial;" id="v-0" class="relative">
<fieldset class="flex gap-x-2 flex-col gap-y-1">
<fieldset class="flex flex-col gap-y-1 gap-x-4">
<!--v-if--><label class="relative flex items-start flex-row">
<div class="flex items-center h-5"><button tabindex="-1" data-orientation="vertical" class="rounded-sm ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary size-4" id="v-0:1" role="checkbox" type="button" aria-checked="false" aria-required="false" data-state="unchecked" data-reka-collection-item="">
<!---->
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0:1" class="block font-medium text-default">Option 1</p>
<p for="v-0:1" class="block font-medium text-red">Option 1</p>
<!--v-if-->
</div>
</label><label class="relative flex items-start flex-row">
@@ -1010,7 +1010,7 @@ exports[`CheckboxGroup > renders with ui correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0:2" class="block font-medium text-default">Option 2</p>
<p for="v-0:2" class="block font-medium text-red">Option 2</p>
<!--v-if-->
</div>
</label><label class="relative flex items-start flex-row">
@@ -1019,7 +1019,7 @@ exports[`CheckboxGroup > renders with ui correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0:3" class="block font-medium text-default">Option 3</p>
<p for="v-0:3" class="block font-medium text-red">Option 3</p>
<!--v-if-->
</div>
</label>

View File

@@ -189,7 +189,7 @@ exports[`CheckboxGroup > renders with description slot correctly 1`] = `
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0-0:1" class="block font-medium text-default">Option 1</p>
<!--v-if-->
<p class="text-muted">Description slot</p>
</div>
</label><label class="relative flex items-start flex-row">
<div class="flex items-center h-5"><button tabindex="-1" data-orientation="vertical" class="rounded-sm ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary size-4" id="v-0-0:2" role="checkbox" type="button" aria-checked="false" aria-required="false" data-state="unchecked" data-reka-collection-item="">
@@ -198,7 +198,7 @@ exports[`CheckboxGroup > renders with description slot correctly 1`] = `
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0-0:2" class="block font-medium text-default">Option 2</p>
<!--v-if-->
<p class="text-muted">Description slot</p>
</div>
</label><label class="relative flex items-start flex-row">
<div class="flex items-center h-5"><button tabindex="-1" data-orientation="vertical" class="rounded-sm ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary size-4" id="v-0-0:3" role="checkbox" type="button" aria-checked="false" aria-required="false" data-state="unchecked" data-reka-collection-item="">
@@ -207,7 +207,7 @@ exports[`CheckboxGroup > renders with description slot correctly 1`] = `
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0-0:3" class="block font-medium text-default">Option 3</p>
<!--v-if-->
<p class="text-muted">Description slot</p>
</div>
</label>
</fieldset>
@@ -507,7 +507,7 @@ exports[`CheckboxGroup > renders with label slot correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0-0:1" class="block font-medium text-default">Option 1</p>
<p for="v-0-0:1" class="block font-medium text-default">Label slot</p>
<!--v-if-->
</div>
</label><label class="relative flex items-start flex-row">
@@ -516,7 +516,7 @@ exports[`CheckboxGroup > renders with label slot correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0-0:2" class="block font-medium text-default">Option 2</p>
<p for="v-0-0:2" class="block font-medium text-default">Label slot</p>
<!--v-if-->
</div>
</label><label class="relative flex items-start flex-row">
@@ -525,7 +525,7 @@ exports[`CheckboxGroup > renders with label slot correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0-0:3" class="block font-medium text-default">Option 3</p>
<p for="v-0-0:3" class="block font-medium text-default">Label slot</p>
<!--v-if-->
</div>
</label>
@@ -573,7 +573,7 @@ exports[`CheckboxGroup > renders with labelKey correctly 1`] = `
exports[`CheckboxGroup > renders with legend slot correctly 1`] = `
"<div tabindex="0" data-orientation="vertical" dir="ltr" style="outline-color: none; outline-style: none; outline-width: initial;" id="v-0-0" class="relative">
<fieldset class="flex gap-x-2 flex-col gap-y-1">
<!--v-if--><label class="relative flex items-start flex-row">
<legend class="mb-1 block font-medium text-default text-sm">Legend slot</legend><label class="relative flex items-start flex-row">
<div class="flex items-center h-5"><button tabindex="-1" data-orientation="vertical" class="rounded-sm ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary size-4" id="v-0-0:1" role="checkbox" type="button" aria-checked="false" aria-required="false" data-state="unchecked" data-reka-collection-item="">
<!---->
<!---->
@@ -994,14 +994,14 @@ exports[`CheckboxGroup > renders with size xs correctly 1`] = `
exports[`CheckboxGroup > renders with ui correctly 1`] = `
"<div tabindex="0" data-orientation="vertical" dir="ltr" style="outline-color: none; outline-style: none; outline-width: initial;" id="v-0-0" class="relative">
<fieldset class="flex gap-x-2 flex-col gap-y-1">
<fieldset class="flex flex-col gap-y-1 gap-x-4">
<!--v-if--><label class="relative flex items-start flex-row">
<div class="flex items-center h-5"><button tabindex="-1" data-orientation="vertical" class="rounded-sm ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary size-4" id="v-0-0:1" role="checkbox" type="button" aria-checked="false" aria-required="false" data-state="unchecked" data-reka-collection-item="">
<!---->
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0-0:1" class="block font-medium text-default">Option 1</p>
<p for="v-0-0:1" class="block font-medium text-red">Option 1</p>
<!--v-if-->
</div>
</label><label class="relative flex items-start flex-row">
@@ -1010,7 +1010,7 @@ exports[`CheckboxGroup > renders with ui correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0-0:2" class="block font-medium text-default">Option 2</p>
<p for="v-0-0:2" class="block font-medium text-red">Option 2</p>
<!--v-if-->
</div>
</label><label class="relative flex items-start flex-row">
@@ -1019,7 +1019,7 @@ exports[`CheckboxGroup > renders with ui correctly 1`] = `
<!---->
</button></div>
<div class="w-full ms-2 text-sm">
<p for="v-0-0:3" class="block font-medium text-default">Option 3</p>
<p for="v-0-0:3" class="block font-medium text-red">Option 3</p>
<!--v-if-->
</div>
</label>