mcpField
B
beam-glow-states

beam-glow-states

github.com/mengto设计与 UI7.1k1.3k 次安装3 天前更新
代码仓库

关于 beam-glow-states

beam-glow-states 是使用 border-beam React 组件呈现加载、选中和活动状态的技能,涵盖效果选择、语义化静态提示、无障碍及渲染检查。

主要功能

  1. 01选择五种光束效果样式
  2. 02配置配色、主题、强度和时长
  3. 03确保无动画时状态仍清晰
  4. 04处理激活和淡出过渡
  5. 05检查无障碍与响应式布局

适用场景

  1. 01在卡片或输入框显示加载状态
  2. 02突出选中的面板或活动控件
  3. 03检查减少动态效果时的动画状态

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mengto/skills --skill beam-glow-states

安装后在 Claude Code 中输入/beam-glow-states确认已加载。

附带文件agents/openai.yamlREFERENCES.md

详细介绍

Beam 光效状态

将 beam 用作装饰性的状态强调。即使没有动画,也要通过文本、形状、对比度以及正确的语义属性,让状态清晰易懂。

以下 API 已针对 border-beam 1.3.0 验证。安装的版本发生变化时,请重新核对官方 README 和导出的类型。

安装和导入

使用仓库的包管理器安装相同的包:

npm install border-beam
pnpm add border-beam
yarn add border-beam
bun add border-beam

此包要求 React 和 React DOM 18 或更高版本。它提供 ESM、CommonJS 和 TypeScript 声明。它会注入组件作用域样式,因此不要单独导入 CSS 文件。

优先使用命名导入:

import { BorderBeam } from "border-beam";
import type {
  BorderBeamProps,
  BorderBeamSize,
  BorderBeamTheme,
  BorderBeamColorVariant,
} from "border-beam";

也支持默认组件导出:

import BorderBeam from "border-beam";

在 Next.js App Router 项目中,请从客户端组件渲染它,因为它使用 React 状态、效果、观察器和动画帧:

"use client";

import { BorderBeam } from "border-beam";

选择效果

size动效最佳用途
sm紧凑的流动边框图标按钮、胶囊按钮、紧凑控件
md完整的流动边框选中卡片、当前面板、主要活动界面
line流动的底边搜索、提示词、输入、进度或命令界面
pulse-inner局限于内部的呼吸光效加载卡片、处理中面板、持续选中状态
pulse-outside向外扩散的呼吸光晕有足够扩散空间的单个突出活动任务或主视觉控件

按状态使用以下默认值:

  • 加载或处理中:pulse-inner,strength={0.55} 到 0.75,duration={2.3} 到 3。
  • 选中或当前状态:md 或 pulse-inner,strength={0.3} 到 0.55,duration={3.2} 到 5。
  • 焦点或短暂的活动反馈:sm 或 line,strength={0.35} 到 0.6。
  • 高优先级实时任务:pulse-outside,strength={0.45} 到 0.7;每个视图中最多只显示一个。

中性产品 UI 使用 colorVariant="mono",冷色调技术状态使用 ocean",紧迫感较强的状态使用 sunset,罕见的高显著性时刻使用 colorful。

从一个已挂载的包装组件开始

让 BorderBeam 保持挂载,并通过切换 active 来控制状态。状态变为 false 时移除它,会跳过内置的淡出效果。

<BorderBeam
  size="pulse-inner"
  colorVariant="ocean"
  theme="dark"
  strength={0.65}
  active={isWorking}
>
  <section className="task-card" aria-busy={isWorking}>
    <p>{isWorking ? "Generating layout options…" : "Layout options ready"}</p>
  </section>
</BorderBeam>

active 会在 0.6s 内淡入,并在 0.5s 内淡出。只有在工作需要与视觉过渡完成时刻同步时,才使用 onActivate 和 onDeactivate。

接入加载状态

添加 beam 前,先确保加载状态如实反映实际情况:

<BorderBeam
  size="pulse-inner"
  colorVariant="ocean"
  strength={0.65}
  active={pending && !reduceMotion}
  onDeactivate={() => {
    // Optional: advance only after the 0.5s beam exit completes.
  }}
>
  <section className="beam-surface" aria-busy={pending}>
    <span className="status-dot" aria-hidden="true" />
    <span>{pending ? "Building preview…" : "Preview ready"}</span>
  </section>
</BorderBeam>
  • 显示可见的状态标签或进度值;绝不要只用移动边缘提示加载。
  • 对于大约在 150ms 或更短时间内完成的操作,避免显示 beam。
  • 显示后,让加载界面至少保持约 400ms 到 600ms,以避免闪烁。
  • 在待处理和完成状态之间保持布局不变。
  • 确保取消、重试和错误控件仍可使用。效果图层已设置 pointer-events: none。

如果工作与单个输入框或提示词栏相关,请使用 line。如果整张卡片都处于忙碌状态,请使用 pulse-inner。

接入选中或当前状态

同时使用组件状态和语义状态:

<BorderBeam
  size="md"
  colorVariant="mono"
  staticColors
  duration={4.2}
  strength={0.42}
  active={selected && !reduceMotion}
  className="beam-card"
>
  <button
    type="button"
    className="beam-surface"
    aria-pressed={selected}
    onClick={onSelect}
  >
    {label}
  </button>
</BorderBeam>
  • 对标签页、listbox 选项、网格单元格及类似的选择控件,使用 aria-selected。
  • 对当前页面、步骤、日期或位置,使用 aria-current。
  • 仅对切换按钮使用 aria-pressed。
  • 保留静态的选中背景或轮廓。beam 应用于增强提示,而不是独自承载含义。
  • 放慢持续显示的选中 beam。较快的默认流动速度应留给加载或短暂激活状态。

对于大型集合,仅让新选中的项目播放动画 800ms 到 1200ms,然后保留静态选中样式。不要让每个选中项目都无限期地显示 beam。

焦点与激活状态

由于所有标准的 HTMLDivElement 属性和捕获处理器都会被转发,因此请在包装元素上跟踪焦点:

const [focused, setFocused] = useState(false);

<BorderBeam
  size="sm"
  colorVariant="mono"
  strength={0.45}
  active={focused && !reduceMotion}
  className="beam-inline"
  onFocusCapture={() => setFocused(true)}
  onBlurCapture={(event) => {
    const next = event.relatedTarget as Node | null;
    if (!next || !event.currentTarget.contains(next)) setFocused(false);
  }}
>
  <button className="beam-surface">Run</button>
</BorderBeam>

保留常规的 :focus-visible 轮廓。仅指针悬停不应触发高强度光束;按下状态仍应立即提供缩放、填充或对比度反馈。

状态重叠时,请明确解决冲突:

const beamState =
  pending ? "loading" :
  selected ? "selected" :
  focused ? "focus" :
  "idle";

const beamProps = {
  loading: {
    size: "pulse-inner",
    colorVariant: "ocean",
    duration: 2.6,
    strength: 0.65,
  },
  selected: {
    size: "md",
    colorVariant: "mono",
    duration: 4.2,
    strength: 0.42,
    staticColors: true,
  },
  focus: {
    size: "sm",
    colorVariant: "mono",
    duration: 2.4,
    strength: 0.45,
    staticColors: true,
  },
} as const;

const activeProps = beamState === "idle" ? null : beamProps[beamState];

<BorderBeam
  {...(activeProps ?? { size: "md" as const })}
  active={activeProps !== null && !reduceMotion}
>
  <div className="beam-surface" data-state={beamState}>
    {children}
  </div>
</BorderBeam>

除非产品的状态模型另有规定,否则优先级依次为:加载高于选中,选中高于焦点,焦点高于悬停。

处理减少动态效果设置

在 prefers-reduced-motion: reduce 下,脉冲预设会停止动画。旋转和线条预设也应由使用方禁用。请使用项目的媒体查询 Hook 或简易客户端 Hook:

function useReducedMotion() {
  const [reduced, setReduced] = useState(false);

  useEffect(() => {
    const media = window.matchMedia("(prefers-reduced-motion: reduce)");
    const update = () => setReduced(media.matches);
    update();
    media.addEventListener("change", update);
    return () => media.removeEventListener("change", update);
  }, []);

  return reduced;
}

在子表面提供静态回退样式:

.beam-surface {
  border: 1px solid rgb(255 255 255 / 0.12);
}

[data-state="selected"] {
  border-color: rgb(140 155 255 / 0.7);
  box-shadow: 0 0 0 3px rgb(100 120 255 / 0.12);
}

:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  [data-state="loading"] {
    border-color: rgb(100 150 255 / 0.68);
  }
}

API 参考

属性类型默认值约定
childrenReactNode必填内容由一个生成的 div 包裹
size"sm" | "md" | "line" | "pulse-outside" | "pulse-inner""md"效果系列和几何预设
colorVariant"colorful" | "mono" | "ocean" | "sunset""colorful"光束调色板
theme"dark" | "light" | "auto""dark"根据背景调整不透明度和颜色处理
strengthnumber1光束图层的不透明度;限制在 0–1;不会改变子元素的不透明度
durationnumber1.96 旋转,3.1 线条,2.3 脉冲动画周期,单位为秒
activebooleantrue启动淡入或淡出,并控制持续动画
borderRadiusnumber自动检测包装元素的圆角半径,单位为像素
brightnessnumber因预设而异,通常为 1.3发光亮度倍率
saturationnumber因主题而异,深色主题通常为 1.2发光饱和度倍率
hueRangenumber30色相偏移范围,单位为度;line 的上限为 13
staticColorsbooleanfalse禁用色相偏移,但不禁用移动或脉冲动画
classNamestring—生成的包装元素上的类名
styleCSSProperties—生成的包装元素上的内联样式
onActivate() => void—0.6s 淡入完成时触发
onDeactivate() => void—0.5s 淡出完成时触发

即使 staticColors 为 false,mono 也始终使用静态颜色。转发的 ref 指向包装元素。其他标准 HTMLDivElement 属性和事件也会被转发。

该包还导出 sizePresets、sizeThemePresets 和已弃用的 themeColors。请将它们视为实现参考;优先使用组件属性,而不要修改导出的预设对象。

注意包装元素

  • BorderBeam 会渲染一个 div。请将其放在 li、td 或 label 等必需的语义化父元素内;不要用它替代这些元素。
  • 包装元素默认采用块级布局。紧凑控件请使用 display: inline-block 或 inline-flex,卡片请使用 width: 100%。
  • 请让第一个子元素与包装元素的边界对齐。如果子元素较小而包装元素被拉伸,光束就会围绕空白区域显示。
  • 边框圆角会从第一个子元素的计算后左上角圆角读取。如果各角圆角不同、圆角在运行时发生变化,或后续加载的样式导致检测不可靠,请显式设置 borderRadius。
  • sm、md、line 和 pulse-inner 会裁剪溢出内容。如果菜单或工具提示必须显示在包装元素之外,请勿将其放入这些包装元素内。
  • pulse-outside 使用 overflow: visible。其子元素必须是不透明的,以免内部光晕透出;周围布局也必须允许光晕溢出。
  • 请为 pulse-outside 的子元素添加独立的细微 1px 边框或内嵌环形边框。该预设不会绘制单独的静止细线,这是有意为之。
.beam-inline {
  display: inline-block;
}

.beam-card {
  display: block;
  width: 100%;
}

.beam-surface {
  width: 100%;
  border-radius: inherit;
  background: rgb(18 18 20);
}

保持克制

  • 每个视口只使用一条主导的动画光束。多条光束同时运行会削弱层级感,并增加绘制开销。
  • 调整亮度或饱和度之前,优先调整 strength。
  • 选择光束应比加载光束更慢、更柔和。
  • 不要同时使用完整光束、另一条动画渐变边框、大面积脉动阴影和移动背景。
  • 让 pulse-outside 延伸到真正的空白区域;切勿意外裁切。
  • 预期脉冲实例会共用一个帧率受限的动画循环,并在移出屏幕时暂停。旋转和线条使用 CSS 动画,同样会在组件移出屏幕时暂停。

验证

测试:

  • 初始未激活、淡入、持续激活、淡出和快速状态反转。
  • 加载成功、出错、重试和取消,期间不应突然卸载。
  • aria-busy、aria-selected、aria-current 或 aria-pressed 语义是否正确。
  • 禁用光束以及启用减少动态效果时的键盘焦点。
  • 在实际表面上测试深色、浅色和 auto 主题。
  • 在 320、768 和 1440 宽度下测试 sm、md、line、pulse-inner 和 pulse-outside。
  • 边框圆角对齐、父级溢出、脉冲外侧的不透明子元素以及紧凑包装器的尺寸。
  • 长标签、200% 缩放、大量列表项、移出屏幕后暂停、路由清理和控制台错误。

将 REFERENCES.md 保留为仅含链接的来源列表。

评论

支持 Markdown