replace el-button-group with ToggleGroup

This commit is contained in:
pa
2026-01-08 19:50:28 +09:00
committed by Natsumi
parent 9735073c7a
commit 914fea6ccf
11 changed files with 448 additions and 187 deletions

View File

@@ -0,0 +1,57 @@
<script setup>
import { ToggleGroupRoot, useForwardPropsEmits } from 'reka-ui';
import { cn } from '@/lib/utils';
import { provide } from 'vue';
import { reactiveOmit } from '@vueuse/core';
const props = defineProps({
rovingFocus: { type: Boolean, required: false },
disabled: { type: Boolean, required: false },
orientation: { type: String, required: false },
dir: { type: String, required: false },
loop: { type: Boolean, required: false },
asChild: { type: Boolean, required: false },
as: { type: null, required: false },
name: { type: String, required: false },
required: { type: Boolean, required: false },
type: { type: String, required: false },
modelValue: { type: null, required: false },
defaultValue: { type: null, required: false },
class: { type: null, required: false },
variant: { type: null, required: false },
size: { type: null, required: false },
spacing: { type: Number, required: false, default: 0 }
});
const emits = defineEmits(['update:modelValue']);
provide('toggleGroup', {
variant: props.variant,
size: props.size,
spacing: props.spacing
});
const delegatedProps = reactiveOmit(props, 'class', 'size', 'variant');
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<ToggleGroupRoot
v-slot="slotProps"
data-slot="toggle-group"
:data-size="size"
:data-variant="variant"
:data-spacing="spacing"
:style="{
'--gap': spacing
}"
v-bind="forwarded"
:class="
cn(
'group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md data-[spacing=default]:data-[variant=outline]:shadow-xs',
props.class
)
">
<slot v-bind="slotProps" />
</ToggleGroupRoot>
</template>

View File

@@ -0,0 +1,45 @@
<script setup>
import { ToggleGroupItem, useForwardProps } from 'reka-ui';
import { cn } from '@/lib/utils';
import { inject } from 'vue';
import { reactiveOmit } from '@vueuse/core';
import { toggleVariants } from '@/components/ui/toggle';
const props = defineProps({
value: { type: null, required: true },
disabled: { type: Boolean, required: false },
asChild: { type: Boolean, required: false },
as: { type: null, required: false },
class: { type: null, required: false },
variant: { type: null, required: false },
size: { type: null, required: false }
});
const context = inject('toggleGroup');
const delegatedProps = reactiveOmit(props, 'class', 'size', 'variant');
const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<ToggleGroupItem
v-slot="slotProps"
data-slot="toggle-group-item"
:data-variant="context?.variant || variant"
:data-size="context?.size || size"
:data-spacing="context?.spacing"
v-bind="forwardedProps"
:class="
cn(
toggleVariants({
variant: context?.variant || variant,
size: context?.size || size
}),
'w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10',
'data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l',
props.class
)
">
<slot v-bind="slotProps" />
</ToggleGroupItem>
</template>

View File

@@ -0,0 +1,2 @@
export { default as ToggleGroup } from './ToggleGroup.vue';
export { default as ToggleGroupItem } from './ToggleGroupItem.vue';

View File

@@ -0,0 +1,35 @@
<script setup>
import { Toggle, useForwardPropsEmits } from 'reka-ui';
import { cn } from '@/lib/utils';
import { reactiveOmit } from '@vueuse/core';
import { toggleVariants } from '.';
const props = defineProps({
defaultValue: { type: Boolean, required: false },
modelValue: { type: [Boolean, null], required: false },
disabled: { type: Boolean, required: false, default: false },
asChild: { type: Boolean, required: false },
as: { type: null, required: false },
name: { type: String, required: false },
required: { type: Boolean, required: false },
class: { type: null, required: false },
variant: { type: null, required: false, default: 'default' },
size: { type: null, required: false, default: 'default' }
});
const emits = defineEmits(['update:modelValue']);
const delegatedProps = reactiveOmit(props, 'class', 'size', 'variant');
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<Toggle
v-slot="slotProps"
data-slot="toggle"
v-bind="forwarded"
:class="cn(toggleVariants({ variant, size }), props.class)">
<slot v-bind="slotProps" />
</Toggle>
</template>

View File

@@ -0,0 +1,25 @@
import { cva } from 'class-variance-authority';
export { default as Toggle } from './Toggle.vue';
export const toggleVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
{
variants: {
variant: {
default: 'bg-transparent',
outline:
'border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground'
},
size: {
default: 'h-9 px-2 min-w-9',
sm: 'h-8 px-1.5 min-w-8',
lg: 'h-10 px-2.5 min-w-10'
}
},
defaultVariants: {
variant: 'default',
size: 'default'
}
}
);