unnamed-ui
输入控件

Block Input

Input component with support for single-line and multiline modes, icons, and various states

"use client";

import { BlockInput } from "@/components/composed/block-input/block-input";

export function BlockInputDemo() {
  return (
    <div className="flex flex-col gap-4 max-w-md">
      <BlockInput placeholder="试试输入点什么..." />
    </div>
  );
}

Block Input 组件是一个功能强大的输入框组件,支持单行和多行输入模式,可配置前后缀图标,并提供多种状态样式。适用于表单、搜索框、评论输入等场景。

概述

  • 单行/多行模式:支持单行输入和多行文本输入切换
  • 前后缀图标:支持在输入框前后添加图标或自定义元素
  • 多种状态:支持默认、hover、focus、error、disabled 等状态
  • 圆角样式:支持常规圆角和全圆角两种风格
  • 主题集成:使用 CSS 变量系统,自动适配主题
  • 类型安全:完整的 TypeScript 类型定义

快速开始

import { BlockInput } from "@/registry/wuhan/composed/block-input";

export function Example() {
  return (
    <div className="flex flex-col gap-4">
      <BlockInput placeholder="请输入内容..." />
      <BlockInput 
        placeholder="多行输入..." 
        multiline 
        rows={3} 
      />
    </div>
  );
}

特性

  • 灵活的输入模式:通过 multiline 属性切换单行和多行输入
  • 图标支持prefixsuffix 属性支持添加任意 React 元素
  • 状态管理:内置 focus 状态管理,支持外部控制
  • 样式定制:使用 CSS 变量实现主题化,易于定制
  • 完整的表单支持:支持所有标准的 input/textarea 属性

安装

pnpm dlx shadcn@latest add "http://localhost:3000/r/wuhan/block-input.json"

代码演示

基础用法

基础输入框和带图标的输入框。

基础输入框:
带前缀图标:
带后缀图标:
前后缀图标:
"use client";

import { Search, User } from "lucide-react";
import { BlockInput } from "@/components/composed/block-input/block-input";

export function BlockInputDefault() {
  return (
    <div className="flex flex-col gap-4 max-w-md">
      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          基础输入框:
        </span>
        <BlockInput placeholder="请输入内容..." />
      </div>

      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          带前缀图标:
        </span>
        <BlockInput
          placeholder="搜索..."
          prefix={<Search className="h-4 w-4" />}
        />
      </div>

      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          带后缀图标:
        </span>
        <BlockInput
          placeholder="输入用户名..."
          suffix={<User className="h-4 w-4" />}
        />
      </div>

      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          前后缀图标:
        </span>
        <BlockInput
          placeholder="搜索用户..."
          prefix={<Search className="h-4 w-4" />}
          suffix={<User className="h-4 w-4" />}
        />
      </div>
    </div>
  );
}

不同状态

输入框的各种状态展示。

默认状态:
危险状态(错误):
禁用状态:
"use client";

import { BlockInput } from "@/components/composed/block-input/block-input";

export function BlockInputStates() {
  return (
    <div className="flex flex-col gap-4 max-w-md">
      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          默认状态:
        </span>
        <BlockInput placeholder="默认输入框" />
      </div>

      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          危险状态(错误):
        </span>
        <BlockInput placeholder="错误输入框" danger />
      </div>

      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          禁用状态:
        </span>
        <BlockInput placeholder="禁用输入框" disabled value="无法编辑" />
      </div>
    </div>
  );
}

多行输入

多行文本输入模式。

多行输入(3行):
多行输入(5行):
"use client";

import { BlockInput } from "@/components/composed/block-input/block-input";

export function BlockInputMultiline() {
  return (
    <div className="flex flex-col gap-4 max-w-md">
      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          多行输入(3行):
        </span>
        <BlockInput multiline rows={3} placeholder="请输入多行文本..." />
      </div>

      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          多行输入(5行):
        </span>
        <BlockInput multiline rows={5} placeholder="请输入更多内容..." />
      </div>
    </div>
  );
}

圆角样式

常规圆角和全圆角样式对比。

常规圆角:
全圆角:
"use client";

import { BlockInput } from "@/components/composed/block-input/block-input";

export function BlockInputRounded() {
  return (
    <div className="flex flex-col gap-4 max-w-md">
      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          常规圆角:
        </span>
        <BlockInput placeholder="常规圆角输入框" />
      </div>

      <div className="flex flex-col gap-2">
        <span className="text-sm text-[var(--Text-text-secondary)]">
          全圆角:
        </span>
        <BlockInput placeholder="全圆角输入框" fullRounded />
      </div>
    </div>
  );
}

API

BlockInput

输入框组件,支持单行和多行模式。

Props

PropTypeDefaultDescription
valuestring-输入框的值
onChange(value: string) => void-值变化回调
placeholderstring-占位符文本
prefixReactNode-前缀图标或元素
suffixReactNode-后缀图标或元素
multilinebooleanfalse是否为多行输入
rowsnumber3多行输入的行数
dangerbooleanfalse是否为危险状态(错误)
disabledbooleanfalse是否禁用
fullRoundedbooleanfalse是否为全圆角
classNamestring-自定义类名
inputClassNamestring-输入框的类名
autoFocusboolean-自动聚焦
maxLengthnumber-最大长度
typestring"text"输入类型(仅单行输入有效)
onBlur() => void-失焦回调
onFocus() => void-聚焦回调
onKeyDown(e: KeyboardEvent) => void-键盘按下回调

Example

import { BlockInput } from "@/registry/wuhan/composed/block-input";
import { Search, Send } from "lucide-react";

function SearchForm() {
  const [value, setValue] = React.useState("");

  return (
    <div className="flex flex-col gap-4">
      {/* 带搜索图标的输入框 */}
      <BlockInput
        value={value}
        onChange={setValue}
        placeholder="搜索..."
        prefix={<Search className="h-4 w-4" />}
      />
      
      {/* 多行输入 */}
      <BlockInput
        multiline
        rows={4}
        placeholder="请输入评论..."
        suffix={<Send className="h-4 w-4 cursor-pointer" />}
      />
      
      {/* 错误状态 */}
      <BlockInput
        danger
        placeholder="输入有误"
        value="invalid@"
      />
      
      {/* 全圆角样式 */}
      <BlockInput
        fullRounded
        placeholder="全圆角输入框"
      />
    </div>
  );
}

CSS 变量

组件使用以下 CSS 变量来实现主题化:

变量名描述使用场景
--text-primary主要文本颜色输入的文本
--text-secondary次要文本颜色前后缀图标
--text-placeholder占位符颜色placeholder 文本
--background-primary主要背景色输入框背景
--border-secondary次要边框颜色默认和禁用状态边框
--border-brand品牌边框颜色hover 和 focus 状态边框
--border-error错误边框颜色danger 状态边框
--radius-lg大圆角常规圆角样式

设计指南

何时使用

  • 需要用户输入单行或多行文本时
  • 需要搜索功能时(配合搜索图标)
  • 需要表单输入时
  • 需要评论或反馈输入时

最佳实践

  1. 合理使用占位符:占位符应简洁明了,提示用户应该输入什么内容
  2. 适当添加图标:图标可以增强输入框的语义,但不要过度使用
  3. 及时反馈错误:使用 danger 属性配合错误提示,帮助用户快速定位问题
  4. 控制输入长度:使用 maxLength 属性限制输入长度,避免超长输入
  5. 选择合适的圆角:全圆角适合简洁现代的设计,常规圆角适合大多数场景

可访问性

  • 组件支持键盘导航
  • 支持 disabled 状态,禁用时正确显示视觉反馈
  • 建议配合 label 元素使用,提供更好的可访问性
  • 错误状态应配合错误提示文本,不要仅依赖颜色

常见问题

Q: 如何实现受控组件?

A: 使用 valueonChange 属性:

const [value, setValue] = React.useState("");

<BlockInput value={value} onChange={setValue} />

Q: 如何自定义聚焦时的边框颜色?

A: 修改 --border-brand CSS 变量:

.custom-input {
  --border-brand: #your-color;
}

Q: 多行输入如何自动调整高度?

A: 当前版本不支持自动高度,可以通过 rows 属性设置固定行数,或使用 inputClassName 自定义样式。

Q: 如何在输入框后添加按钮?

A: 使用 suffix 属性:

<BlockInput
  suffix={
    <button onClick={handleSubmit}>
      <Send className="h-4 w-4" />
    </button>
  }
/>

原语组件

BlockInput 组件基于以下原语组件构建:

  • BlockInputContainerPrimitive: 容器组件,处理边框和状态样式
  • BlockInputPrefixPrimitive: 前缀容器组件
  • BlockInputSuffixPrimitive: 后缀容器组件
  • BlockInputPrimitive: 单行输入框原语
  • BlockTextareaPrimitive: 多行输入框原语

如需更灵活的定制,可以直接使用这些原语组件。