reui

Icon Tile

Icon Tile — кастомный компонент, портированный из ReUI (keenthemes/reui, MIT).

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

src/reui/icon-tile/IconTile.vue

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

const props = withDefaults(
  defineProps<{
    /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
    class?: HTMLAttributes["class"]
    variant?: IconTileVariants["variant"]
    size?: IconTileVariants["size"]
    radius?: IconTileVariants["radius"]
    asChild?: boolean
  }>(),
  {
    variant: "outline",
    size: "default",
    radius: "default",
    asChild: false,
  }
)
</script>

<template>
  <Primitive
    as="span"
    :as-child="props.asChild"
    data-slot="icon-tile"
    :data-variant="props.variant"
    :data-size="props.size"
    :class="
      cn(
        iconTileVariants({ variant: props.variant, size: props.size, radius: props.radius }),
        props.class
      )
    "
  >
    <slot />
  </Primitive>
</template>

src/reui/icon-tile/index.ts

export { default as IconTile } from "./IconTile.vue"
export { iconTileVariants, type IconTileVariants } from "./variants"

src/reui/icon-tile/variants.ts

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

/**
 * Перенесено дословно из ReUI (registry-reui/bases/radix/reui/icon-tile.tsx, MIT).
 *
 * cva-блоки — чистые JS-объекты и переносятся между React и Vue без единой
 * правки. Это и есть главный рычаг всего порта: вся визуальная семантика
 * живёт здесь, а фреймворк-специфичной остаётся только разметка.
 */
export const iconTileVariants = cva(
  [
    "relative inline-flex shrink-0 items-center justify-center align-middle",
    "size-(--icon-tile-size) rounded-(--icon-tile-radius)",
    "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-(--icon-tile-icon-size)",
  ],
  {
    variants: {
      variant: {
        /** Plain bordered surface. The quiet default for list rows and toolbars. */
        outline: "border border-border bg-background dark:bg-input/32",
        /** Raised muted fill with a background-colored ring. Reads as a physical chip. */
        elevated:
          "border-2 border-background bg-muted text-accent-foreground shadow-[0_1px_3px_0_rgb(0_0_0/0.14)] dark:border",
        /**
         * Tinted double container: an opacity-filled outer ring with no border
         * around a bordered inner card, all derived from `currentColor`. The
         * quiet, colorful sibling of `frame`. Retint with a text color class.
         */
        soft: [
          "isolate p-(--icon-tile-inset) text-primary bg-current/10",
          "after:absolute after:-z-10 after:inset-(--icon-tile-inset)",
          "after:rounded-[calc(var(--icon-tile-radius)-var(--icon-tile-inset))]",
          "after:border after:border-current/20 after:bg-current/5",
        ],
        /** Filled tone with a contrasting glyph. Retint with `bg-*` + a text color. */
        solid: "bg-primary text-primary-foreground",
        /** Double container - a muted ring around an inset card, matching Frame. */
        frame: [
          "isolate border border-border bg-muted/50 p-(--icon-tile-inset)",
          "after:absolute after:-z-10 after:inset-(--icon-tile-inset)",
          "after:rounded-[calc(var(--icon-tile-radius)-var(--icon-tile-inset))]",
          "after:border after:border-border after:bg-card after:shadow-xs",
        ],
      },
      size: {
        xs: "[--icon-tile-size:--spacing(6)] [--icon-tile-icon-size:--spacing(3.5)] [--icon-tile-inset:--spacing(0.5)]",
        sm: "[--icon-tile-size:--spacing(8)] [--icon-tile-icon-size:--spacing(4)] [--icon-tile-inset:--spacing(0.5)]",
        default:
          "[--icon-tile-size:--spacing(10)] [--icon-tile-icon-size:--spacing(4.5)] [--icon-tile-inset:--spacing(0.75)]",
        lg: "[--icon-tile-size:--spacing(12)] [--icon-tile-icon-size:--spacing(5.5)] [--icon-tile-inset:--spacing(0.75)]",
        xl: "[--icon-tile-size:--spacing(14)] [--icon-tile-icon-size:--spacing(7)] [--icon-tile-inset:--spacing(1)]",
      },
      /**
       * `default`: active style radius. `full`: circular.
       * The plain value is the fallback outside a style scope; the `style-*`
       * tokens win by specificity inside one, and survive the registry
       * transform as the single resolved value per generated style.
       */
      radius: {
        default:
          "[--icon-tile-radius:var(--radius-md)] style-vega:[--icon-tile-radius:var(--radius-md)] style-nova:[--icon-tile-radius:var(--radius-md)] style-maia:[--icon-tile-radius:var(--radius-2xl)] style-lyra:[--icon-tile-radius:0px] style-mira:[--icon-tile-radius:var(--radius-md)] style-luma:[--icon-tile-radius:var(--radius-2xl)] style-rhea:[--icon-tile-radius:var(--radius-2xl)] style-sera:[--icon-tile-radius:0px]",
        full: "[--icon-tile-radius:calc(infinity*1px)]",
      },
    },
    defaultVariants: {
      variant: "outline",
      size: "default",
      radius: "default",
    },
  }
)

export type IconTileVariants = VariantProps<typeof iconTileVariants>

Установка

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

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

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

  • class-variance-authority
  • reka-ui

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