Skip to content

Commit 23a0418

Browse files
committed
feat(frontend): implement ButtonGroup component with variants
1 parent 3b22e37 commit 23a0418

File tree

6 files changed

+110
-9
lines changed

6 files changed

+110
-9
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script setup lang="ts">
2+
import type { HTMLAttributes } from "vue"
3+
import type { ButtonGroupVariants } from "."
4+
import { cn } from "@/lib/utils"
5+
import { buttonGroupVariants } from "."
6+
7+
const props = defineProps<{
8+
class?: HTMLAttributes["class"]
9+
orientation?: ButtonGroupVariants["orientation"]
10+
}>()
11+
</script>
12+
13+
<template>
14+
<div
15+
role="group"
16+
data-slot="button-group"
17+
:data-orientation="props.orientation"
18+
:class="cn(buttonGroupVariants({ orientation: props.orientation }), props.class)"
19+
>
20+
<slot />
21+
</div>
22+
</template>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script setup lang="ts">
2+
import type { SeparatorProps } from "reka-ui"
3+
import type { HTMLAttributes } from "vue"
4+
import { reactiveOmit } from "@vueuse/core"
5+
import { cn } from "@/lib/utils"
6+
import { Separator } from '@/components/ui/separator'
7+
8+
const props = withDefaults(defineProps<SeparatorProps & { class?: HTMLAttributes["class"] }>(), {
9+
orientation: "vertical",
10+
})
11+
const delegatedProps = reactiveOmit(props, "class")
12+
</script>
13+
14+
<template>
15+
<Separator
16+
data-slot="button-group-separator"
17+
v-bind="delegatedProps"
18+
:orientation="props.orientation"
19+
:class="cn(
20+
'bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto',
21+
props.class,
22+
)"
23+
/>
24+
</template>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script setup lang="ts">
2+
import type { PrimitiveProps } from "reka-ui"
3+
import type { HTMLAttributes } from "vue"
4+
import type { ButtonGroupVariants } from "."
5+
import { Primitive } from "reka-ui"
6+
import { cn } from "@/lib/utils"
7+
8+
interface Props extends PrimitiveProps {
9+
class?: HTMLAttributes["class"]
10+
orientation?: ButtonGroupVariants["orientation"]
11+
}
12+
13+
const props = withDefaults(defineProps<Props>(), {
14+
as: "div",
15+
})
16+
</script>
17+
18+
<template>
19+
<Primitive
20+
role="group"
21+
data-slot="button-group"
22+
:data-orientation="props.orientation"
23+
:as="as"
24+
:as-child="asChild"
25+
:class="cn('bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*=\'size-\'])]:size-4', props.class)"
26+
>
27+
<slot />
28+
</Primitive>
29+
</template>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { VariantProps } from "class-variance-authority"
2+
import { cva } from "class-variance-authority"
3+
4+
export { default as ButtonGroup } from "./ButtonGroup.vue"
5+
export { default as ButtonGroupSeparator } from "./ButtonGroupSeparator.vue"
6+
export { default as ButtonGroupText } from "./ButtonGroupText.vue"
7+
8+
export const buttonGroupVariants = cva(
9+
"flex w-fit items-stretch [&>*:focus-visible]:z-10 [&>*:focus-visible]:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
10+
{
11+
variants: {
12+
orientation: {
13+
horizontal:
14+
"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
15+
vertical:
16+
"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
17+
},
18+
},
19+
defaultVariants: {
20+
orientation: "horizontal",
21+
},
22+
},
23+
)
24+
25+
export type ButtonGroupVariants = VariantProps<typeof buttonGroupVariants>

services/frontend/src/components/ui/separator/Separator.vue

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
<script setup lang="ts">
2-
import type { HTMLAttributes } from 'vue'
3-
import { reactiveOmit } from '@vueuse/core'
4-
import { Separator, type SeparatorProps } from 'reka-ui'
5-
import { cn } from '@/lib/utils'
2+
import type { SeparatorProps } from "reka-ui"
3+
import type { HTMLAttributes } from "vue"
4+
import { reactiveOmit } from "@vueuse/core"
5+
import { Separator } from "reka-ui"
6+
import { cn } from "@/lib/utils"
67
78
const props = withDefaults(defineProps<
8-
SeparatorProps & { class?: HTMLAttributes['class'] }
9+
SeparatorProps & { class?: HTMLAttributes["class"] }
910
>(), {
10-
orientation: 'horizontal',
11+
orientation: "horizontal",
1112
decorative: true,
1213
})
1314
14-
const delegatedProps = reactiveOmit(props, 'class')
15+
const delegatedProps = reactiveOmit(props, "class")
1516
</script>
1617

1718
<template>
@@ -20,7 +21,7 @@ const delegatedProps = reactiveOmit(props, 'class')
2021
v-bind="delegatedProps"
2122
:class="
2223
cn(
23-
`bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px`,
24+
'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
2425
props.class,
2526
)
2627
"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { default as Separator } from './Separator.vue'
1+
export { default as Separator } from "./Separator.vue"

0 commit comments

Comments
 (0)