primitives

Input Group

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

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

src/ui/input-group/InputGroup.vue

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

const props = defineProps<{
  /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div
    data-slot="input-group"
    role="group"
    :class="
      cn(
        'group/input-group cn-input-group relative flex w-full min-w-0 items-center outline-none has-[>textarea]:h-auto',
        props.class
      )
    "
  >
    <slot />
  </div>
</template>

src/ui/input-group/InputGroupAddon.vue

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

const props = withDefaults(
  defineProps<{
    /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
    class?: HTMLAttributes["class"]
    align?: InputGroupAddonVariants["align"]
  }>(),
  {
    align: "inline-start",
  }
)

/** Клик по обёртке фокусирует соседний `<input>`, кроме кликов по кнопке. */
function onClick(e: MouseEvent) {
  if ((e.target as HTMLElement).closest("button")) {
    return
  }
  ;(e.currentTarget as HTMLElement).parentElement?.querySelector("input")?.focus()
}
</script>

<template>
  <div
    role="group"
    data-slot="input-group-addon"
    :data-align="props.align"
    :class="cn(inputGroupAddonVariants({ align: props.align }), props.class)"
    @click="onClick"
  >
    <slot />
  </div>
</template>

src/ui/input-group/InputGroupButton.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { Button, type ButtonVariants } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import { inputGroupButtonVariants, type InputGroupButtonVariants } from "./variants"

const props = withDefaults(
  defineProps<{
    /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
    class?: HTMLAttributes["class"]
    type?: "button" | "submit" | "reset"
    variant?: ButtonVariants["variant"]
    size?: InputGroupButtonVariants["size"]
  }>(),
  {
    type: "button",
    variant: "ghost",
    size: "xs",
  }
)
</script>

<template>
  <Button
    :type="props.type"
    :data-size="props.size"
    :variant="props.variant"
    :class="cn(inputGroupButtonVariants({ size: props.size }), props.class)"
  >
    <slot />
  </Button>
</template>

src/ui/input-group/InputGroupInput.vue

<script setup lang="ts">
import type { HTMLAttributes, InputHTMLAttributes } from "vue"
import { Input } from "@/components/ui/input"
import { cn } from "@/lib/utils"

const props = defineProps<{
  /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
  class?: HTMLAttributes["class"]
  type?: InputHTMLAttributes["type"]
}>()
</script>

<template>
  <Input
    data-slot="input-group-control"
    :type="props.type"
    :class="cn('cn-input-group-input flex-1', props.class)"
  />
</template>

src/ui/input-group/InputGroupText.vue

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

const props = defineProps<{
  /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <span :class="cn('cn-input-group-text flex items-center [&_svg]:pointer-events-none', props.class)">
    <slot />
  </span>
</template>

src/ui/input-group/InputGroupTextarea.vue

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

const props = defineProps<{
  /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <Textarea
    data-slot="input-group-control"
    :class="cn('cn-input-group-textarea flex-1 resize-none', props.class)"
  />
</template>

src/ui/input-group/index.ts

export { default as InputGroup } from "./InputGroup.vue"
export { default as InputGroupAddon } from "./InputGroupAddon.vue"
export { default as InputGroupButton } from "./InputGroupButton.vue"
export { default as InputGroupText } from "./InputGroupText.vue"
export { default as InputGroupInput } from "./InputGroupInput.vue"
export { default as InputGroupTextarea } from "./InputGroupTextarea.vue"
export {
  inputGroupAddonVariants,
  type InputGroupAddonVariants,
  inputGroupButtonVariants,
  type InputGroupButtonVariants,
} from "./variants"

src/ui/input-group/variants.ts

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

/**
 * Перенесено дословно из shadcn (registry/bases/radix/ui/input-group.tsx, MIT).
 *
 * cva-блоки — чистые JS-объекты и переносятся между React и Vue без единой
 * правки. Вся визуальная семантика живёт здесь, а фреймворк-специфичной
 * остаётся только разметка.
 */
export const inputGroupAddonVariants = cva(
  "cn-input-group-addon flex cursor-text items-center justify-center select-none",
  {
    variants: {
      align: {
        "inline-start": "cn-input-group-addon-align-inline-start order-first",
        "inline-end": "cn-input-group-addon-align-inline-end order-last",
        "block-start":
          "cn-input-group-addon-align-block-start order-first w-full justify-start",
        "block-end":
          "cn-input-group-addon-align-block-end order-last w-full justify-start",
      },
    },
    defaultVariants: {
      align: "inline-start",
    },
  }
)

export type InputGroupAddonVariants = VariantProps<typeof inputGroupAddonVariants>

export const inputGroupButtonVariants = cva(
  "cn-input-group-button flex items-center shadow-none",
  {
    variants: {
      size: {
        xs: "cn-input-group-button-size-xs",
        sm: "cn-input-group-button-size-sm",
        "icon-xs": "cn-input-group-button-size-icon-xs",
        "icon-sm": "cn-input-group-button-size-icon-sm",
      },
    },
    defaultVariants: {
      size: "xs",
    },
  }
)

export type InputGroupButtonVariants = VariantProps<typeof inputGroupButtonVariants>

Установка

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

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

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

  • class-variance-authority

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