primitives

Tabs

Tabs — базовый примитив RevueUI (Reka UI + shadcn-совместимый API).

Загрузка превью…

src/ui/tabs/Tabs.vue

<script setup lang="ts">
/**
 * Порт базового радикс-слоя (registry/bases/radix/ui/tabs.tsx, MIT).
 * Radix TabsPrimitive -> reka-ui Tabs*, один в один.
 */
import type { HTMLAttributes } from "vue"
import { TabsRoot } from "reka-ui"
import { cn } from "@/lib/utils"

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes["class"]
    orientation?: "horizontal" | "vertical"
  }>(),
  {
    orientation: "horizontal",
  }
)
</script>

<template>
  <TabsRoot
    data-slot="tabs"
    :data-orientation="props.orientation"
    :orientation="props.orientation"
    :class="cn('cn-tabs group/tabs flex data-horizontal:flex-col', props.class)"
  >
    <slot />
  </TabsRoot>
</template>

src/ui/tabs/TabsContent.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import type { TabsContentProps } from "reka-ui"
import { TabsContent } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<
  TabsContentProps & { class?: HTMLAttributes["class"] }
>()
</script>

<template>
  <TabsContent
    data-slot="tabs-content"
    :value="props.value"
    :force-mount="props.forceMount"
    :class="cn('cn-tabs-content flex-1 outline-none', props.class)"
  >
    <slot />
  </TabsContent>
</template>

src/ui/tabs/TabsList.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { TabsList } from "reka-ui"
import { cn } from "@/lib/utils"
import { tabsListVariants, type TabsListVariants } from "./variants"

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes["class"]
    variant?: TabsListVariants["variant"]
  }>(),
  {
    variant: "default",
  }
)
</script>

<template>
  <TabsList
    data-slot="tabs-list"
    :data-variant="props.variant"
    :class="cn(tabsListVariants({ variant: props.variant }), props.class)"
  >
    <slot />
  </TabsList>
</template>

src/ui/tabs/TabsTrigger.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import type { TabsTriggerProps } from "reka-ui"
import { TabsTrigger } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<
  TabsTriggerProps & { class?: HTMLAttributes["class"] }
>()
</script>

<template>
  <TabsTrigger
    data-slot="tabs-trigger"
    :value="props.value"
    :disabled="props.disabled"
    :class="
      cn(
        'cn-tabs-trigger relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0',
        'group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent',
        'data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground',
        'after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100',
        props.class
      )
    "
  >
    <slot />
  </TabsTrigger>
</template>

src/ui/tabs/index.ts

export { default as Tabs } from "./Tabs.vue"
export { default as TabsContent } from "./TabsContent.vue"
export { default as TabsList } from "./TabsList.vue"
export { default as TabsTrigger } from "./TabsTrigger.vue"
export { tabsListVariants, type TabsListVariants } from "./variants"

src/ui/tabs/variants.ts

import { cva, type VariantProps } from "class-variance-authority"

/**
 * Перенесено дословно из registry/bases/radix/ui/tabs.tsx (MIT).
 */
export const tabsListVariants = cva(
  "cn-tabs-list group/tabs-list inline-flex w-fit items-center justify-center text-muted-foreground group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col",
  {
    variants: {
      variant: {
        default: "cn-tabs-list-variant-default bg-muted",
        line: "cn-tabs-list-variant-line gap-1 bg-transparent",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
)

export type TabsListVariants = VariantProps<typeof tabsListVariants>

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/tabs.json

Зависимости реестра

npm-зависимости

  • class-variance-authority
  • reka-ui

Источник: порт из ReUI (Keenthemes, MIT)