primitives

Item

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

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

src/ui/item/Item.vue

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

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes["class"]
    variant?: ItemVariants["variant"]
    size?: ItemVariants["size"]
    asChild?: boolean
  }>(),
  {
    variant: "default",
    size: "default",
    asChild: false,
  }
)
</script>

<template>
  <Primitive
    data-slot="item"
    :data-variant="props.variant"
    :data-size="props.size"
    as="div"
    :as-child="props.asChild"
    :class="cn(itemVariants({ variant: props.variant, size: props.size, class: props.class }))"
  >
    <slot />
  </Primitive>
</template>

src/ui/item/ItemActions.vue

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

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

<template>
  <div data-slot="item-actions" :class="cn('cn-item-actions flex items-center', props.class)">
    <slot />
  </div>
</template>

src/ui/item/ItemContent.vue

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

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

<template>
  <div
    data-slot="item-content"
    :class="
      cn(
        'cn-item-content flex flex-1 flex-col [&+[data-slot=item-content]]:flex-none',
        props.class
      )
    "
  >
    <slot />
  </div>
</template>

src/ui/item/ItemDescription.vue

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

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

<template>
  <p
    data-slot="item-description"
    :class="
      cn(
        'cn-item-description line-clamp-2 font-normal [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary',
        props.class
      )
    "
  >
    <slot />
  </p>
</template>

src/ui/item/ItemFooter.vue

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

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

<template>
  <div
    data-slot="item-footer"
    :class="cn('cn-item-footer flex basis-full items-center justify-between', props.class)"
  >
    <slot />
  </div>
</template>

src/ui/item/ItemGroup.vue

<script setup lang="ts">
/**
 * Порт базового радикс-слоя (registry/bases/radix/ui/item.tsx, MIT).
 * Презентационная композиция; `ItemSeparator` — тонкая обёртка над
 * `Separator` (registry/bases/radix/ui/separator.tsx, портирован ранее).
 */
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"

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

<template>
  <div
    role="list"
    data-slot="item-group"
    :class="cn('cn-item-group group/item-group flex w-full flex-col', props.class)"
  >
    <slot />
  </div>
</template>

src/ui/item/ItemHeader.vue

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

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

<template>
  <div
    data-slot="item-header"
    :class="cn('cn-item-header flex basis-full items-center justify-between', props.class)"
  >
    <slot />
  </div>
</template>

src/ui/item/ItemMedia.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
import { itemMediaVariants, type ItemMediaVariants } from "./variants"

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

<template>
  <div
    data-slot="item-media"
    :data-variant="props.variant"
    :class="cn(itemMediaVariants({ variant: props.variant, class: props.class }))"
  >
    <slot />
  </div>
</template>

src/ui/item/ItemSeparator.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
import { Separator } from "@/components/ui/separator"

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

<template>
  <Separator
    data-slot="item-separator"
    orientation="horizontal"
    :class="cn('cn-item-separator', props.class)"
  />
</template>

src/ui/item/ItemTitle.vue

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

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

<template>
  <div
    data-slot="item-title"
    :class="cn('cn-item-title line-clamp-1 flex w-fit items-center', props.class)"
  >
    <slot />
  </div>
</template>

src/ui/item/index.ts

export { default as Item } from "./Item.vue"
export { default as ItemActions } from "./ItemActions.vue"
export { default as ItemContent } from "./ItemContent.vue"
export { default as ItemDescription } from "./ItemDescription.vue"
export { default as ItemFooter } from "./ItemFooter.vue"
export { default as ItemGroup } from "./ItemGroup.vue"
export { default as ItemHeader } from "./ItemHeader.vue"
export { default as ItemMedia } from "./ItemMedia.vue"
export { default as ItemSeparator } from "./ItemSeparator.vue"
export { default as ItemTitle } from "./ItemTitle.vue"
export {
  itemMediaVariants,
  itemVariants,
  type ItemMediaVariants,
  type ItemVariants,
} from "./variants"

src/ui/item/variants.ts

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

/**
 * Перенесено дословно из registry/bases/radix/ui/item.tsx (MIT).
 */
export const itemVariants = cva(
  "cn-item group/item flex w-full flex-wrap items-center transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors",
  {
    variants: {
      variant: {
        default: "cn-item-variant-default",
        outline: "cn-item-variant-outline",
        muted: "cn-item-variant-muted",
      },
      size: {
        default: "cn-item-size-default",
        sm: "cn-item-size-sm",
        xs: "cn-item-size-xs",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

export type ItemVariants = VariantProps<typeof itemVariants>

export const itemMediaVariants = cva(
  "cn-item-media flex shrink-0 items-center justify-center [&_svg]:pointer-events-none",
  {
    variants: {
      variant: {
        default: "cn-item-media-variant-default",
        icon: "cn-item-media-variant-icon",
        image: "cn-item-media-variant-image",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
)

export type ItemMediaVariants = VariantProps<typeof itemMediaVariants>

Установка

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

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

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

  • class-variance-authority
  • reka-ui

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