PVQ-UI
v1.4.3
Gitee

文档

PVQ-UI 的开发方案、项目规则、组件清单与调用方法。文档为代码唯一真源,本页直接渲染仓库中的真实 Markdown。

设计令牌与组件清单

PVQ-UI 设计令牌与组件清单(模块文档 / 组件 API 说明)

状态:组件 API 人类可读说明(库 1.4.0) 机器可读唯一真源:site/inc/components.json(官网画廊数据驱动,新增组件只改 JSON,画廊自动出现)。本文件引用 JSON,不再手抄示例。 用途:人类查阅组件 API / 设计令牌;判断"某组件是否已存在"以 components.json 为准。 关联:《PVQ-UI项目规则.md》(铁律,§2.3 定义 JSON 为唯一真源)、《PVQ-UI组件库开发方案.md》§3.5(架构)、《组件提取对照表.md》(旧→新映射)、《PVQ-UI组件库调用手册.md》(插件实操)


0. 文档地位

  • 本文件是 pvq-ui 组件 API 的人类可读说明;机器可读的唯一真源是 site/inc/components.json(含组件 id / 名称 / 层 / 稳定性 / 附加说明 note / 示例 HTML,官网画廊遍历它渲染;stability 严格二值 stable/experimental)。
  • 任何"这个组件库有没有 / 叫什么类"的问题,以 components.json 为准;它里面没有的,才进入"新增组件"流程(先文档 → 再代码,见《PVQ-UI项目规则》§1)。本文件的示例仅作阅读参考,真值随 JSON 同步。
  • 稳定性标记:stable(承诺不破坏改)/ experimental(接口可能调整,引用建议锁版本)。首版基线全部 stable。

1. 当前库版本

  • 1.4.0(当前库版本,2026-09-19 发布;升版本 + 部署全新目录 pvq-ui/v1.4.0/,细节见 CHANGELOG 1.4.0 块):设计令牌化收口 + 真源规范化(零视觉变化,一处例外)。① base/admin 层硬编码色值令牌化:新增 --pvq-border-hover / --pvq-border-hover-strong / --pvq-surface-active / --pvq-primary-alt / --pvq-danger-hover / --pvq-warning-strong / --pvq-warning-gradient(-hover) / --pvq-warning-shadow 等令牌,语义色深浅派生统一改 color-mix()(与等价 rgba 逐位相同),全库规则体内已无非豁免字面量;② 补齐被引用却缺失的令牌:--pvq-surface-alt(有一处无兜底、背景静默失效)、--pvq-radius-md、--pvq-text-strong、--pvq-toast-offset-x/-y;其中 --pvq-text-strong 由蓝调兜底改为与 --pvq-text 同值(唯一可见变化:Checkbox/Radio/Bookmark/DataGrid 的 hover 强调文字由蓝转绿);③ components.json 的 stability 二值化(严格 stable/experimental)+ 新增 note 字段承载来源/版本,画廊标签改为「层 · 稳定性(note)」拼接渲染;④ 命名受控例外登记(pvq-cb-variant-* / pvq-rb-variant-*);⑤ 仓库一致性修正(版本七处、组件真源判据、部署 URL 子目录、移除 latest 承诺、官网文档白名单与快速开始示例)。令牌清单见 §2.8,调用方需把 PVQ_UI_Loader::enqueue() 与 loader DEFAULT_VERSION 升至 '1.4.0'。
  • 1.3.1(2026-09-19 发布;升版本 + 部署全新目录 pvq-ui/v1.3.1/,细节见 CHANGELOG 1.3.1 块):锚点浮层 Popover(§3.1 Base 层新增,experimental,回流自 pvq-weixinyuedu):以元素为锚、脱离文档流、按需显隐的浮层(术语解释 / 作者卡 / 预览 / 迷你详情)。类 .pvq-popover + __body / __foot / __arrow,修饰符 --open(打开态,JS 加)/--above(JS 判定的上方位置);开关只有两态——hidden 属性(彻底不显示)+ --open(淡入)。定位用 position:fixed + getBoundingClientRect() 实时算并写内联 top/left,不依赖任何祖先 position;视口边缘自动翻转 + 双向夹取;JS 双入口 PVQUI.popover(anchor, opts) 与声明式 [data-pvq-popover="<浮层 id>"](initPopovers() 随 initAll 自动接管、幂等);事件 pvq-popover:open / pvq-popover:close(reason ∈ pointer/focus/click/escape/outside/api)。落库决策与完整契约见《PVQ-UI回流落库-Popover锚点浮层.md》,用法见调用手册 §4.7。调用方需把 PVQ_UI_Loader::enqueue() 与 loader DEFAULT_VERSION 升至 '1.3.1';版本七处(两个 loader 的 DEFAULT_VERSION、assets/css/pvq-ui.css 与 assets/js/pvq-ui.js 的 @version、site/inc/config.php 的 PVQ_UI_VERSION、site/inc/components.json 的 version、readme.md 当前版本与示例)已同步,另加 CHANGELOG.md 版本块与本文件。
  • 1.3.0(2026-09-19 发布;升版本 + 部署全新目录 pvq-ui/v1.3.0/,细节见 CHANGELOG 1.3.0 块):① 浮层通知 Toast(§3.1 Base 层新增,experimental,回流自 pvq-weixinyuedu):双入口 PVQUI.toast(options) 与 [data-pvq-toast],四语义 success/info/warning/error,同屏至多 4 条、超出挤走最旧,悬停暂停计时,事件 pvq-toast:open/pvq-toast:close;② 横幅可关闭(§3.1 Banner 增强):待办 / 提醒类横幅末尾加 .pvq-banner__close[data-pvq-banner-close],initBanners() 自动接管并派发 pvq-banner:close,不含关闭按钮的横幅行为不变;③ 二次确认弹窗幂等修复:initConfirms() 的 document 级委托补 confirmsBound 守卫(此前随 initAll 在 resize 上重跑会逐次叠加等价监听),兑现本条与调用手册承诺的「幂等」。调用方需把 PVQ_UI_Loader::enqueue() 与 loader DEFAULT_VERSION 升至 '1.3.0';版本七处(两个 loader 的 DEFAULT_VERSION、assets/css/pvq-ui.css 与 assets/js/pvq-ui.js 的 @version、site/inc/config.php 的 PVQ_UI_VERSION、site/inc/components.json 的 version、readme.md 当前版本与示例)已同步。
  • 1.2.11(2026-09-05 固化升版,无功能改动,细节见 CHANGELOG 1.2.10/1.2.11 块)。1.2.10 批次(因 CDN immutable 长缓存,1.2.10 覆盖部署未对端侧生效,随 1.2.11 全新目录才对外可见):Range 数值框可编辑 + 拖滑块修复(§3.1 Range,v1.2.10)、二次确认弹窗 Confirm Modal(§3.1 表单区,v1.2.10)、Select 玻璃磨砂下拉 --glass(§3.1 Select,v1.2.10)、权重输入框 Weight(§3.4,v1.2.10,随 1.2.11 固化发布)。
  • 1.2.9。在 1.2.7(Field/Input 校验状态、附加变体、密码显隐切换、Collapse 修复)基础上:① Field/Input 输入框图标缩进适配 FA 7.2.0:--has-icon/--has-toggle 的 padding 令牌化推导为 calc(offset + size*1.25 + gap) ≈ 42px,修复 FA 7.2.0 图标盒宽导致的压字;② Field/Input 成功文案槽 .pvq-field__success:与 .pvq-field__error 完全对称(绿字 var(--pvq-success) + fa-circle-check + flex 对齐),成功态文案不再借 .pvq-field__help + 内联 color:var(--pvq-success)(避免违反令牌化纪律、且与帮助文案语义超载、无法共存)。同版保留 1.2.7 的 .pvq-field--error(红框+红字+红辉光)/.pvq-field--success(绿框+绿辉光)/.pvq-field__label--required/pvq-field__error 等;详见 §3.1。1.2.6 之前:1.2.5(Input/ColorField/Button 选择器特异性加固)删除按钮二次确认、1.1.x 演进。旧插件名仅在《组件提取对照表.md》§6 作为迁移映射出现。
  • ③ 搜索组件 Search(base 层,1.2.8 新增):独立 .pvq-search,形状归库、颜色归令牌 --pvq-search-accent(默认 --pvq-primary 绿);功能变体 --with-btn / --with-filter(复用库 .pvq-select)/ --loading / --sm,形状变体 --pill / --underline / --ghost / --glass;库 JS initSearches() 派发 pvq-search 事件供插件接检索。详见 §3.1 Search 条目。
  • ④ 前端迁移组件(1.2.9 并入):把 wolai 前端组件收为库默认,含 进度条 Progress(.pvq-progress + --lg / --danger)、书签 Bookmark(.pvq-bookmark + __image/__url/__title/__description)、卡片化表格 Table(.pvq-table 单元格独立圆角卡片、表头绿底、--striped 斑马纹、__col--right/center 列对齐、caption)、数据表格 DataGrid(.pvq-datagrid 含工具栏搜索/排序三态/筛选双下拉/重置 + 入场动画,搜索/筛选为自包含可展开胶囊、点击空白收起)。颜色全部走 --pvq-* 令牌(森林绿),零硬编码。JS initTables()(入场动画,[data-pvq-table] 触发)与 initDataGrids()(搜索/排序/筛选/重置,[data-pvq-datagrid] 触发)随 initAll 自动调用、幂等。详见 §3.4。注意 Checkbox / Radio 在 1.2.9 末次修订中已从 frontend 层提升到 base 层(§3.1 表单区),原因:pvq-wp 后台只 enqueue(['admin']),frontend 层 CSS 后台不加载;二者是 WP 后台原生表单控件,须与 Switch/Input/Field/Select 同归 base 层(pvq-ui.css)。
  • 旧插件名(.pvq-btn-primary、.pvq-card-header、.pvq-connection-status 等)不在本表,仅在《组件提取对照表.md》§6 作为迁移映射出现。

2. 设计令牌(:root 全集,base 层 pvq-ui.css)

取值以 wolai admin-settings.css:11-62 为基线;标注【合并】的为从 pvq-wp / threads 吸收(库首版新增)。库是纯令牌提供方,不假设 --pvq-theme-* 存在。令牌只加不删(见《项目规则》§2.4)。

2.1 主色系(森林绿)

令牌 值 说明
--pvq-primary #608062 主色
--pvq-primary-hover #4f6b51 主色 hover
--pvq-primary-light rgba(96,128,98,0.08) 主色浅底
--pvq-primary-soft rgba(96,128,98,0.12) 主色柔底
--pvq-primary-glow rgba(96,128,98,0.20) 主色辉光(focus / 阴影)
--pvq-primary-gradient linear-gradient(135deg,#608062,#7a9e7c) 主色渐变
--pvq-primary-gradient-hover linear-gradient(135deg,#4f6b51,#6b8e6d) 主色渐变 hover

2.2 语义色

令牌 值 说明
--pvq-success #4a8c5c 成功
--pvq-success-light rgba(74,140,92,0.08) 成功浅底
--pvq-danger #c45454 危险
--pvq-danger-light rgba(196,84,84,0.08) 危险浅底
--pvq-warning #c49a2e 警告
--pvq-warning-light rgba(196,154,46,0.08) 警告浅底
--pvq-info #5a8a9a 信息
--pvq-info-light rgba(90,138,154,0.08) 信息浅底

2.3 中性色

令牌 值 说明
--pvq-bg #f4f5f2 页面背景
--pvq-surface #ffffff 卡片 / 表面
--pvq-surface-hover #fafaf8 表面 hover
--pvq-border #dfe3dc 边框
--pvq-border-light #eaecea 浅边框 / 分隔
--pvq-border-strong【v1.2.9】 #cdd2db 悬停 / 聚焦时的稍深边框(前端组件 Bookmark、Search 等)
--pvq-text #1e2a1f 主文本
--pvq-text-secondary #5c6b5e 次文本
--pvq-text-muted #94a396 弱文本

2.4 圆角

令牌 值
--pvq-radius-sm 8px
--pvq-radius 12px
--pvq-radius-lg 16px
--pvq-radius-xl 20px
--pvq-radius-pill【合并 pvq-wp】 999px

2.5 阴影

令牌 值
--pvq-shadow-sm 0 1px 3px rgba(30,42,31,0.04)
--pvq-shadow 0 2px 8px rgba(30,42,31,0.06)
--pvq-shadow-md 0 4px 20px rgba(30,42,31,0.08)
--pvq-shadow-lg 0 8px 32px rgba(30,42,31,0.12)
--pvq-shadow-primary 0 4px 16px rgba(96,128,98,0.25)

2.6 缓动与过渡

令牌 值
--pvq-ease cubic-bezier(0.4,0,0.2,1)
--pvq-ease-bounce cubic-bezier(0.34,1.56,0.64,1)
--pvq-ease-magnet cubic-bezier(0.34,1.3,0.55,1)
--pvq-ease-smooth cubic-bezier(0.25,0.1,0.25,1)
--pvq-transition all 0.25s var(--pvq-ease)
--pvq-transition-fast all 0.15s var(--pvq-ease)
--pvq-transition-slow all 0.4s var(--pvq-ease-smooth)

2.7 尺寸补充

令牌 值 说明
--pvq-input-h【合并 threads】 40px 输入控件高度基准
--pvq-input-icon-size【v1.2.8】 14px 输入框内图标字号,同步 .pvq-input__icon { font-size };参与图标缩进 calc 推导
--pvq-input-icon-offset【v1.2.8】 12px 输入框内图标距左边界距离,同步 .pvq-input__icon { left };参与图标缩进 calc 推导
--pvq-input-icon-gap【v1.2.8】 12px 图标盒右界与输入文字的最小安全间隙;FA 7.2.0 给 .fas 强制 width:1.25em 使图标盒加宽,故需抬到 12px(详见 §3.1 Input 条目「FA 7.2.0 图标盒宽适配」)

2.8 v1.4.0 新增令牌(同值迁移 + 补齐被引用却缺失的令牌)

来源:H1「base/admin 层硬编码色值令牌化」与缺失令牌审计。全部为同值迁移(除 --pvq-text-strong 见下),视觉不变;令牌只加不删(§2.4 精神)。

令牌 值 说明 / 原字面值
--pvq-radius-md 8px 补齐:.pvq-table 早已引用 var(--pvq-radius-md, 8px)、文档也写 --pvq-radius-md,但 :root 从未定义它;现正式登记
--pvq-surface-alt #f8f9f6 补齐:.pvq-collapse__header 等引用 var(--pvq-surface-alt, #f8f9f6),且有一处无兜底导致背景静默失效;现定义于 :root
--pvq-text-strong #1e2a1f 补齐并纠色:原为 var(--pvq-text-strong, #0b1b2f / #1f3a4b / #0b1e2b),兜底值是蓝调(wolai 蓝 demo 残留),与森林绿主色系冲突;现统一为与 --pvq-text 同值
--pvq-border-hover #c8d0c6 原字面值(按钮 / 次级按钮 hover 边框)
--pvq-border-hover-strong #b8c4b9 原字面值(输入类控件 hover 边框:Input / Textarea / Affix / Select / ColorField)
--pvq-surface-active #f8f9f7 原字面值(按钮 hover 底色,与 --pvq-surface-hover 不同值,故单列)
--pvq-primary-alt #7a9e7c 主色渐变的第二停靠色(原写死在 --pvq-primary-gradient 与 help 背景渐变里)
--pvq-danger-hover #b34747 原字面值(.pvq-btn--armed hover 底色/边框)
--pvq-warning-strong #8a6d14 原字面值(.pvq-status--warning 文字色,深琥珀)
--pvq-warning-gradient linear-gradient(135deg,#f59e0b,#d97706) 原字面值(.pvq-btn--warning 底色)
--pvq-warning-gradient-hover linear-gradient(135deg,#d97706,#b45309) 原字面值(warning hover)
--pvq-warning-shadow rgba(217,119,6,0.3) 原字面值(warning hover 投影)
--pvq-toast-offset-x / --pvq-toast-offset-y 20px 补齐:Toast 文档称「布局令牌默认 20px」,此前只是 var() 兜底值、并非真实令牌;现定义于 :root,后台覆写 body.wp-admin{--pvq-toast-offset-y:44px} 照旧生效

同值迁移的实现方式:语义色的深浅派生(主色/成功/危险/警告/信息的 4%~28% 半透明底与边框)一律改写为 color-mix(in srgb, var(--pvq-<语义色>) N%, transparent)。在 sRGB 下与等价 rgba() 逐位相同,但改语义色令牌时派生色自动跟随,不再出现「改了主色、边框还是旧色」的问题。


3. 组件清单(按层)

层说明:pvq-ui(base) 全场景;pvq-ui-admin / pvq-ui-editor / pvq-ui-frontend 为场景层,依赖 base。

3.1 Base 层(pvq-ui.css)

按钮 Button · stable

  • 类:.pvq-btn
  • 修饰符:--primary --secondary --danger --warning --ghost --sm --icon
  • 规格:圆角 9px · 字重 550 · 8/18 padding · 默认透明边框 hover 显现;primary 带渐变底 + 微阴影
  • 组合:.pvq-btn-group(按钮组,右对齐)
  • 删除按钮:复用 .pvq-btn--danger + fa-trash 图标;破坏性操作建议加 data-pvq-confirm 二次确认(见下「删除按钮二次确认」)
  • 示例:
    <button class="pvq-btn pvq-btn--primary"><i class="fas fa-save"></i> 保存</button>
    <div class="pvq-btn-group">
      <button class="pvq-btn pvq-btn--secondary">取消</button>
      <button class="pvq-btn pvq-btn--primary">保存</button>
    </div>
    <!-- 删除按钮:文字版 / 图标-only 版 / 小号版 -->
    <button class="pvq-btn pvq-btn--danger"><i class="fas fa-trash"></i> 删除</button>
    <button class="pvq-btn pvq-btn--danger pvq-btn--icon"><i class="fas fa-trash"></i></button>
    <button class="pvq-btn pvq-btn--danger pvq-btn--sm"><i class="fas fa-trash"></i> 删除</button>

删除按钮二次确认(破坏性操作防护)· stable(1.2.0 新增行为)

  • 行为:给任意按钮加 data-pvq-confirm="确认文案",库 JS 接管二次确认,避免误触删除 / 整页表单提交。任意 .pvq-btn(不限于 danger)均可加。
  • 交互(库 JS,捕获阶段 preventDefault + stopPropagation,见下「WordPress 注意」):
    1. 首次点击:仅进入「确认态」——按钮就地变为实色危险红(.pvq-btn--armed)+ 文案替换为确认语(如「确定删除?」),不触发原行为;设 3 秒自动取消。
    2. 确认态内再次点击:恢复外观并放行原行为(表单提交 / 插件自有 click 监听照常执行)。
    3. 超时(3s)/ 按 Esc / 点击页面其它处:自动取消,恢复原样。
  • 修饰符:.pvq-btn--armed(确认态实色红,库自动加 / 去,插件勿手写)。
  • 示例:
    <button class="pvq-btn pvq-btn--danger" data-pvq-confirm="确定删除该项?">
      <i class="fas fa-trash"></i> 删除
    </button>
  • WordPress 注意:若按钮位于 WP <form> 内(如 upload.php),首次点击由库在捕获阶段 preventDefault,避免整页重载;确认态内第二次点击才放行。插件无需额外处理。
  • 设计意图:破坏性操作统一防护,各插件不重复造轮子;纯 data-* 增强,不破坏既有按钮样式与提交逻辑。

卡片 Card · stable

  • 类:.pvq-card
  • 子元素:.pvq-card__header .pvq-card__icon .pvq-card__icon--{primary,success,warning,info,danger} .pvq-card__title .pvq-card__desc .pvq-card__action
  • 示例:
    <div class="pvq-card">
      <div class="pvq-card__header">
        <span class="pvq-card__icon pvq-card__icon--primary"><i class="fas fa-cog"></i></span>
        <div>
          <h3 class="pvq-card__title">连接设置</h3>
          <p class="pvq-card__desc">配置账号信息</p>
        </div>
      </div>
      <div class="pvq-card__action">
        <button class="pvq-btn pvq-btn--primary">保存</button>
      </div>
    </div>

表单 Field / Input · stable

  • 类:.pvq-field .pvq-field__label .pvq-field__help .pvq-field__error .pvq-field__success .pvq-input .pvq-input__wrap .pvq-input__wrap--has-icon .pvq-input__icon .pvq-input__toggle;附加变体:前后缀 .pvq-affix-group .pvq-affix .pvq-affix--suffix、输入组 .pvq-input-group .pvq-input-group__btn(.pvq-input-group__btn--ghost)、清除 .pvq-input__clear + .pvq-input__wrap--has-clear、密码显隐切换 .pvq-input__toggle + .pvq-input__wrap--has-toggle(由 pvq-ui.js 自动初始化,切换 type=password/text)

  • 校验状态(行内校验,纯 CSS、零 JS):给 .pvq-field 加 .pvq-field--error / .pvq-field--success 即切换输入框边框色与 focus 辉光(红/绿),并配 .pvq-field__error(红色错误文案槽,常驻红字,配 fa-circle-exclamation)或 .pvq-field__success(绿色成功文案槽,常驻绿字,配 fa-circle-check,与错误槽完全对称);.pvq-field__label--required 在 label 后追加红色 * 必填标记。错误态须「红字 + 红框 + 红 focus 辉光」一整套,缺一不可。成功态用 .pvq-field__success 而非 .pvq-field__help,避免与帮助文案语义重载、且二者可并存。

  • 选择器特异性:覆盖 input 边框/辉光的规则一律写成 input.pvq-input.pvq-input(0,3,1),压过库默认 input.pvq-input.pvq-input(0,2,1),否则 error/success 边框/辉光不变色(同 components.json 校验状态 demo)。

  • 示例:

    <div class="pvq-field">
      <label class="pvq-field__label">API Token</label>
      <div class="pvq-input__wrap pvq-input__wrap--has-icon">
        <i class="pvq-input__icon fas fa-key"></i>
        <input class="pvq-input" type="text" placeholder="请输入">
      </div>
      <p class="pvq-field__help">在设置页获取你的 Token。</p>
    </div>
  • 校验状态示例(error / success + 必填):

    <div class="pvq-field pvq-field--error">
      <label class="pvq-field__label pvq-field__label--required">邮箱地址</label>
      <input class="pvq-input" type="text" value="not-an-email">
      <p class="pvq-field__error"><i class="fas fa-circle-exclamation"></i> 请输入有效的邮箱地址</p>
    </div>
    <div class="pvq-field pvq-field--success">
      <label class="pvq-field__label">数据库连接</label>
      <input class="pvq-input" type="text" value="mysql://127.0.0.1:3306">
      <p class="pvq-field__success"><i class="fas fa-circle-check"></i> 连接测试通过</p>
    </div>
  • 附加变体(前后缀 / 输入组 / 清除 / 密码显隐切换,纯 CSS 零 JS 除外 toggle):

    • 前后缀单位(joined segment):.pvq-affix-group 包 .pvq-affix(前缀,默认)或 .pvq-affix--suffix(后缀),内部 <input class="pvq-input"> 自动去边框 / 去圆角,只剩外层框 + 分隔线。常用于 https:// 前缀、px / % / MB 单位后缀。
    • 输入组(input + 按钮):.pvq-input-group 内放 <input class="pvq-input"> + <button class="pvq-input-group__btn">(配 --ghost 幽灵绿描边),横向组合用于复制 / 搜索。
    • 清除按钮(✕):在 .pvq-input__wrap 上加 .pvq-input__wrap--has-clear,内部放 <button class="pvq-input__clear">(绝对定位在右侧、复用 wrap 的 position:relative),一键清空;padding-right 自动让位给清除按钮。
    • 密码显隐切换(眼睛):在 .pvq-input__wrap 上加 .pvq-input__wrap--has-toggle,内部放 <button class="pvq-input__toggle" type="button" aria-label="显示密码">(绝对定位在右侧),由 pvq-ui.js 自动初始化,点击切换 <input type="password"> ↔ <input type="text"> 并切换图标 fa-eye ↔ fa-eye-slash;padding-right 自动让位给切换按钮,避免密码文本与眼睛重叠。
    • 特异性:affix-group 内部 input、has-clear / has-icon / has-toggle 的 padding 一律写成 input.pvq-input.pvq-input(0,3,1)压过库默认输入样式(0,2,1),否则内部 input 边框残留(三重框)或图标 / 清除按钮 / 切换按钮压字。
    • 【v1.2.8】FA 7.2.0 图标盒宽适配:FA 7.2.0 给所有 .fas 强制 width: var(--fa-width, 1.25em) + text-align: center,图标盒宽 = --pvq-input-icon-size(14px) × 1.25 = 17.5px(旧版 FA 无此约束、盒宽≈字形宽)。.pvq-input__icon 定位于 left:12px,图标右界落在 12 + 17.5 = 29.5px;原 padding-left/right:36px 给文字/切换按钮仅留 36 - 29.5 = 6.5px 间隙,宽字形(fa-id-badge / fa-envelope)会压字。v1.2.8 改为 padding-left/right: calc(var(--pvq-input-icon-offset) + var(--pvq-input-icon-size) * 1.25 + var(--pvq-input-icon-gap)) = 12 + 17.5 + 12 = 41.5px → 42px,间隙恢复 12.5px。图标几何用 --pvq-input-icon-* 令牌化,FA 改图标宽度系数时只改 1.25 一处即可(详见 §2.7 令牌表)。
    • 示例(前后缀 + 输入组 + 清除):
      
      <!-- 前后缀 -->
      <div class="pvq-field">
      <label class="pvq-field__label">站点地址</label>
      <div class="pvq-affix-group">
        <span class="pvq-affix">https://</span>
        <input class="pvq-input" type="text" value="example.com">
      </div>
      </div>
      <div class="pvq-field">
      <label class="pvq-field__label">缩略图宽度</label>
      <div class="pvq-affix-group">
        <input class="pvq-input" type="text" value="320" style="text-align:right">
        <span class="pvq-affix pvq-affix--suffix">px</span>
      </div>
      </div>
    ```

长文本输入框 Textarea · stable

  • 类:.pvq-textarea(配合 .pvq-field 容器使用),变体 .pvq-textarea--sm(小号)。
  • 与 .pvq-input 同源视觉:边框 1.5px、--pvq-radius-sm 圆角、:focus 主色边框 + box-shadow 辉光、::placeholder 弱色;resize: vertical 仅允许纵向拖拽,禁横向。
  • 选择器特异度:textarea.pvq-textarea.pvq-textarea(0,2,1),与库其它表单控件一致,压过 WP 核心(WP 仅对 textarea 有通用 (0,0,1) 规则,被压过)。
  • 示例:
    <div class="pvq-field">
      <label class="pvq-field__label" for="desc">备注</label>
      <textarea class="pvq-textarea" id="desc" placeholder="请输入详细描述…"></textarea>
      <p class="pvq-field__help">支持多行,可纵向拖拽调整高度。</p>
    </div>

选择器 Select(自定义下拉,渐进增强原生 select)· experimental

  • 类:.pvq-select(包裹原生 <select>,库自动初始化).pvq-select__trigger .pvq-select__text .pvq-select__arrow .pvq-select__dropdown .pvq-select__option .pvq-select--open .pvq-select__option--selected .pvq-select__option--disabled .pvq-select--sm(紧凑变体)
  • 结构:.pvq-select 内放一个原生 <select>(保留其 name/value/disabled,表单照常提交);库 JS 自动把它增强为自定义下拉,原生 select 仅视觉隐藏、DOM 仍存在,选中即同步原生 select 的 value 并派发 change。
  • 交互(库 JS,原生事件委托、无 jQuery):点击 trigger 开/关;打开时箭头翻转、空间不足自动向上弹(flip)、右边界贴合、滚动/缩放重定位;键盘 Enter/Space 切换、ArrowDown 打开、Esc 关闭;点击外部关闭;同时只开一个。
  • 可访问性:首版 experimental 为简易键盘(trigger tabindex=0 + Enter/Space/Esc),role=listbox/option、aria-expanded、方向键在选项间移动留待 stable 时补齐。
  • 下拉面板挂 <body>(position:fixed):为绕过 WP metabox 的 overflow:hidden 裁剪,非 jQuery 特性,原生版同样如此。
  • 变体:.pvq-select--sm(紧凑):trigger 高 30px / 字号 13px / padding:5px 10px,并 min-width:0 解除库默认 min-width:160px,适配 WP 后台 tablenav / bulkactions / 媒体工具栏等密集行;下拉面板 min-width:120px。纯 CSS 修饰,pvq-ui.js 只扫描 .pvq-select,--sm 不影响初始化。特异性 .pvq-select--sm .pvq-select__trigger(0,2,0)高于库 .pvq-select__trigger(0,1,0),无需 !important。
  • 变体:.pvq-select--glass(玻璃磨砂下拉,v1.2.10 前端装饰):容器加 pvq-select--glass,body 级下拉面板即半透明磨砂。机制要点:面板由 JS 渲染并挂 <body>、无父级可继承容器类,故 JS 在打开时检测容器上的 pvq-select--glass 并把状态带到面板(加 .pvq-select__dropdown--glass),不能靠后代选择器。样式:半透明白 rgba(255,255,255,.52) + backdrop-filter: blur(20px) saturate(1.4)(@supports 检测 -webkit-/标准前缀,不支持时退回 rgba(255,255,255,.72) 高不透明度,保证文字可读);玻璃态下选项 hover 用 --pvq-primary-light、选中用 --pvq-primary-soft(半透明绿系,补偿透明造成的对比损失)。装饰性变体,需背后有彩色内容才显 blur 效果(后台白底上仅见轻微通透感)。默认下拉保持纸面不透明,不影响存量调用。
  • 示例:
    <div class="pvq-select">
      <select name="threads_sync_settings[mode]">
        <option value="auto">自动同步</option>
        <option value="manual" selected>手动同步</option>
        <option value="off">关闭</option>
      </select>
    </div>

开关 Switch(语义化,纯 CSS)· stable

  • 结构:.pvq-switch 包 <input type="checkbox" class="pvq-switch__input"> + <span class="pvq-switch__slider">
  • 行布局:.pvq-switch-row .pvq-switch-row__label .pvq-switch-row__desc
  • 行为:纯 CSS,由 :checked 控制,零 JS;可访问性最好(真实 checkbox)。
  • 示例:
    <div class="pvq-switch-row">
      <div>
        <div class="pvq-switch-row__label">启用同步</div>
        <div class="pvq-switch-row__desc">开启后自动同步内容</div>
      </div>
      <label class="pvq-switch">
        <input type="checkbox" class="pvq-switch__input" checked>
        <span class="pvq-switch__slider"></span>
      </label>
    </div>
微交互动画(档 2,纯 CSS)
  • 滑块位移由 left 改为 transform: translateX(var(--x)):GPU 加速、不重排;配合 --pvq-ease-bounce 弹簧缓动,开/合"弹一下"。
  • 圆点用 ::before 伪元素(与演示 demo 一致);CSS 变量 --x(位移)和 --s(缩放)定义在 .pvq-switch__slider 上::checked 改 --x:20px、:hover 改 --s:1.12、:active 改 --s:0.9。圆点 ::before 读 var(--x) / var(--s) 组合为单一 transform: translateX(var(--x)) scale(var(--s))。transition 拆为独立属性 transition-property/duration/timing-function(非简写),防 WordPress 全局 *::before { transition: all … } 覆盖弹簧缓动。
  • 开/关换色用实色 --pvq-primary(可 transition 平滑过渡);不再用 --pvq-primary-gradient(CSS 无法对 gradient 做过渡,旧版为瞬间硬切)。
  • 开合光晕:滑块 box-shadow 在 :checked 时播放一次性 pvq-switch-ring 扩散(向外扩 9px 柔光环),起止落回常驻 glow,纯视觉反馈(与演示 demo 一致)。
  • 不开态图标,仅以位置 + 颜色 + 光晕表达状态。
  • 全部动效由库全局 @media (prefers-reduced-motion: reduce) 统一降级(动画/过渡即时,无滑动、无缩放)。

勾选框 Checkbox · stable(1.2.9 并入;末次修订由 frontend 层提升至 base 层)

  • 归属层:base 层(pvq-ui.css)。原因:pvq-wp 后台仅 enqueue(['admin']),pvq-ui-admin 依赖 base,故 base 必随后台加载;Checkbox 是 WP 后台原生表单控件,须与 Switch/Input/Field/Select 同归 base(1.2.9 曾误置于 frontend 层,末次修订已提升)。
  • 结构:.pvq-cb-list(布局容器,仅 display:flex; flex-direction:column; gap; margin-top,不再承载令牌)> label.pvq-cb-item(独立可用:裸 <label class="pvq-cb-item"> 包裹原生 <input> + .pvq-custom-check 即可,无需 .pvq-cb-list 父级)> 隐藏原生 <input type="checkbox"> + span.pvq-custom-check(.pvq-cb-box + span.pvq-cb-mark ✓)+ span.pvq-cb-text。
  • 令牌已提至 :root(全局默认值):--pvq-cb-size(32px)/--pvq-cb-radius(10px)/--pvq-cb-bg(#fff)/--pvq-cb-border/--pvq-cb-checked-bg/--pvq-cb-checked-border/--pvq-cb-checked-shadow(0 6px 14px …)/--pvq-cb-checked-dark/--pvq-cb-ghost-bg/--pvq-cb-ghost-border/--pvq-cb-ripple-bg/--pvq-cb-ripple-ring/--pvq-cb-ripple-checked-bg/--pvq-cb-ripple-spread,均派生自 --pvq-primary。原因:原令牌写在 .pvq-cb-list 内,裸 .pvq-cb-item(无 .pvq-cb-list 父容器)时 var(--pvq-cb-size) 算空 → 勾框尺寸崩掉;提到 :root 后独立 .pvq-cb-item 也能正常工作。--sm/--lg 修饰符仍在其作用域覆盖默认值。--pvq-cb-mark-size 不入 :root(靠 var(...,18px) 兜底 + 变体覆盖)。
  • 三态 :checked / :indeterminate(部分选中,列表页"全选"主框):命中 :indeterminate 时 .pvq-cb-box 绿底 + 隐藏 ✓ 字形 + .pvq-cb-box::after 画一条白色横线(base/ghost/ripple 变体下 .pvq-cb-box 均无 ::after,安全不冲突);WP "全选"主框由 JS 设 indeterminate 属性自动命中。
  • 三变体:pvq-cb-variant-strike(勾选后文字删除线)、pvq-cb-variant-ghost(透明底圆角)、pvq-cb-variant-ripple(圆形 + 扩散波纹);弹性打钩(cubic-bezier(.34,1.56,.64,1))+ 整框脉冲;prefers-reduced-motion 关闭动画。
  • 尺寸变体(在 .pvq-cb-list 上加):--sm(24px)/ 默认(32px)/ --lg(40px),令牌 --pvq-cb-size / --pvq-cb-radius / --pvq-cb-mark-size 控制。
  • 示例:
    <div class="pvq-cb-variant-strike"><div class="pvq-cb-list"><label class="pvq-cb-item"><input type="checkbox" checked><span class="pvq-custom-check"><span class="pvq-cb-box"></span><span class="pvq-cb-mark">✓</span></span><span class="pvq-cb-text">默认选中</span></label></div></div>
    <!-- 尺寸:<div class="pvq-cb-list pvq-cb-list--sm"> … </div> -->
    <!-- 三态:JS 给 input 设 .indeterminate=true → 命中 :indeterminate(横线) -->

单选按钮 Radio · stable(1.2.9 并入;末次修订由 frontend 层提升至 base 层)

  • 归属层:base 层(pvq-ui.css)。原因同 Checkbox(WP 后台原生控件,须随 admin 依赖的 base 加载;1.2.9 曾误置于 frontend 层,末次修订已提升)。
  • 结构:.pvq-rb-group(布局容器,仅 display:flex; flex-direction:column; gap; margin-top,不再承载令牌)> label.pvq-rb-item > 隐藏原生 <input type="radio"> + span.pvq-custom-radio(.pvq-rb-outer + span.pvq-rb-dot) + span.pvq-rb-label。
  • 令牌已提至 :root(全局默认值):--pvq-rb-size(32px)/--pvq-rb-outer-border/--pvq-rb-dot/--pvq-rb-checked-bg/--pvq-rb-checked-border/--pvq-rb-ring/--pvq-rb-checked-dark/--pvq-rb-ripple-checked-bg/--pvq-rb-ripple-spread/--pvq-rb-base-bg,均派生自 --pvq-primary。原因同 Checkbox。--pvq-rb-dot-size 不入 :root(靠 var(...,14px) 兜底 + 变体覆盖)。
  • 四变体:pvq-rb-variant-card(选中高亮整行,:has(input:checked))、pvq-rb-variant-ghost(透明底 + 白点)、pvq-rb-variant-ripple(圆形 + 扩散波纹)、pvq-rb-variant-solid(纯色填充);内点弹性弹入 + 整钮脉冲;prefers-reduced-motion 关闭动画。
  • 尺寸变体(在 .pvq-rb-group 上加):--sm(24px)/ 默认(32px)/ --lg(40px),令牌 --pvq-rb-size / --pvq-rb-dot-size 控制。
  • 示例:
    <div class="pvq-rb-variant-card"><div class="pvq-rb-group"><label class="pvq-rb-item"><input type="radio" name="g" checked><span class="pvq-custom-radio"><span class="pvq-rb-outer"></span><span class="pvq-rb-dot"></span></span><span class="pvq-rb-label">标准套餐</span></label></div></div>

状态指示 Status · stable

  • 类:.pvq-status --{success,warning,error} .pvq-status__dot
  • 示例:<span class="pvq-status pvq-status--success"><span class="pvq-status__dot"></span> 已连接</span>

徽标 Badge · stable【新增】

  • 类:.pvq-badge;可选修饰符 --primary 等(默认主色浅底)
  • 示例:<span class="pvq-badge">v1.3.18</span>

横幅 Banner(原 connection-status)· stable

  • 类:.pvq-banner --{success,danger,warning,info} .pvq-banner__dot .pvq-banner__title .pvq-banner__text .pvq-banner__close(可关闭,本次新增)
  • 映射:connected→--success、disconnected→--danger、unconfigured→--warning
  • 可关闭(新增):待办 / 提醒类横幅末尾放 <button type="button" class="pvq-banner__close" data-pvq-banner-close aria-label="关闭">✕</button>,库 JS initBanners()(随 initAll 自动调用、幂等,用 data-pvq-banner-init 防重复)接管点击:加 --closing → 动画结束移除节点 → 派发 pvq-banner:close(detail: { banner })供插件写入关闭记忆(如 user_meta / localStorage)。纯声明式,插件无需写 JS;不含 __close 的横幅行为完全不变(向后兼容)。
  • 关闭记忆由插件持久化,库不碰任何 storage(避免跨插件猜测键名与越权)。
  • 示例:
    <div class="pvq-banner pvq-banner--warning">
      <span class="pvq-banner__dot"></span>
      <div><div class="pvq-banner__title">尚未配置 Token</div><div class="pvq-banner__text">前往「设置 → 连接」完成授权。</div></div>
      <button type="button" class="pvq-banner__close" data-pvq-banner-close aria-label="关闭">✕</button>
    </div>
    <script>/* 记忆(示例):*/ document.addEventListener('pvq-banner:close', function (e) { /* saveClosed(e.detail.banner.dataset.pvqBannerKey) */ });</script>

提示 Alert(原 test-result)· stable

  • 类:.pvq-alert --{success,error,loading} + 显隐类 .pvq-alert--show
  • 示例:<div class="pvq-alert pvq-alert--show pvq-alert--success"><i class="fas fa-check"></i> 测试通过</div>

浮层通知 Toast · experimental【新增:回流自 pvq-weixinyuedu,待发版固化】

与 Alert / Banner 的分工:toast 只承载「一次操作的即时结论」(短句、短暂停留、自动消失)。结果是一组数据→用页面内常驻区域(如 .pvq-meta-list),toast 只说一句结论;长任务进行中→内联 .pvq-alert--loading;常驻待办→可关闭的 .pvq-banner。

  • 类:.pvq-toast-layer(容器).pvq-toast --{success,error,warning,info}(--danger 为 --error 别名)--leaving(离场态,JS 添加).pvq-toast__icon .pvq-toast__body .pvq-toast__title .pvq-toast__desc .pvq-toast__close
  • 容器由库 JS 自动创建(首次 PVQUI.toast() / initToasts() 时挂到 <body>,幂等、全局唯一),因此 JS 未加载时无 DOM 残留(不对静态 HTML 做破坏性假设)。
  • 层级 z-index: 100002:刻意高于 .pvq-modal 遮罩(100001)。既有三档为 99999 取色面板 / 100000 下拉 / 100001 遮罩;toast 必须压过遮罩,否则「弹窗确认 → 删除成功」这条最高频链路在遮罩关闭前看不到结果反馈。
  • 设计原则:形状归库、颜色归令牌。组件只定义 --pvq-toast-accent(四种变体分别赋 --pvq-success/danger/warning/info),左侧色条与图标色彩全走它,零硬编码。布局令牌 --pvq-toast-offset-y / --pvq-toast-offset-x,默认 20px 为中性值(前台无 admin bar 也不留多余空白);WP 后台由消费方在 body 上覆写 --pvq-toast-offset-y: 44px(≤782px 视口 admin bar 46px)。
  • API:PVQUI.toast(options) → 返回单条实例对象(含 el / close(reason))。options:
字段 类型 默认 说明
type string 'info' success / error / warning / info
title string 必填 主文案(走 textContent,不接受 HTML,防 XSS)
desc string — 次要文案(同样 textContent)
icon string 按 type 取 FA 类 如 'fas fa-circle-check'
duration number success/info 3000、warning 5000、error 8000 毫秒;0 = 不自动关闭(须手动关)
  • 行为:同屏最多 4 条,超出时最旧一条立即离场(reason: 'displace');鼠标悬停暂停倒计时、移开继续;点击 __close 立即关闭(reason: 'close');prefers-reduced-motion 下无位移缩放(animationend 兜底定时器保证节点一定被回收)。
  • 事件(均冒泡):pvq-toast:open / pvq-toast:close,detail: { toast, el, type, reason }。
  • 可访问性:容器 role="region" aria-label="通知"(容器不挂 aria-live——容器插入瞬间被朗读会异常);单条 success/info 用 role="status"(aria-live="polite"),error/warning 用 role="alert"(aria-live="assertive")。
  • 声明式触发(可选用法,便于后端渲染 / 官网 demo):任意元素加 data-pvq-toast 即由 initToasts() 接管,点击触发;参数读 data-pvq-toast-type / -title(缺省用元素文本)/ -desc / -duration。避免 inline handler,与 data-pvq-confirm、data-pvq-modal-open 同范式。
  • 明确不做:点击跳转 / 承载操作按钮 / 进度条型 / 声音或桌面通知。
  • 示例:
    <!-- JS 调用 -->
    <script>
      PVQ_UI_ToastExample();
      function PVQ_UI_ToastExample() {
        PVQUI.toast({ type: 'success', title: '设置已保存' });
        PVQUI.toast({ type: 'error', title: '连接失败', desc: 'Token 无效或已过期', duration: 0 });
      }
    </script>
    <!-- 声明式 -->
    <button type="button" class="pvq-btn pvq-btn--primary" data-pvq-toast data-pvq-toast-type="success" data-pvq-toast-title="已同步 12 条">触发通知</button>
  • 幂等提醒:initAll() 同时绑定在 DOMContentLoaded 与 window resize 上,故 initToasts() 只负责「确保容器存在」,绝不清理正在显示的 toast(否则窗口一缩放通知就被抹掉)。

锚点浮层 Popover · experimental【新增:回流自 pvq-weixinyuedu,待发版固化】

与 Card / Collapse / Confirm Modal / Toast 的分工:popover 以某元素为锚、脱离文档流按需显隐。card 是常驻内容容器(无定位与开合)、collapse 是原地展开会撑高文档流造成布局位移、confirm-modal 是模态阻断交互、toast 固定在角落不锚定触发元素——四者都不能替代「锚定某元素的气泡」(术语解释 / 作者卡 / 预览 / 迷你详情)。

  • 类:.pvq-popover(浮层本体).pvq-popover__body(内容区).pvq-popover__foot(脚注区,可选,border-top 分隔).pvq-popover__arrow(可选小箭头);修饰符 --open(打开态,库 JS 加)、--above(库 JS 判定的上方位置)。
  • 开关契约只有两个状态:hidden 属性 = 彻底不显示(display:none);--open = 淡入显示。库只认这两个,不碰业务。
  • 定位:position: fixed,坐标由库 JS 用 getBoundingClientRect() 算出后写内联 top/left。刻意不用 absolute——那必须假定业务容器是定位上下文,而那是业务的自由,库不该假定。默认贴锚点下方,下方放不下且上方够高时自动翻转并加 --above;水平与垂直双向夹取,不飞出视口。
  • 设计原则:形状归库、颜色归令牌。只暴露布局令牌 --pvq-popover-width(默认 min(24rem, calc(100vw - 2rem)))与 --pvq-popover-z(默认 90),色值全走 --pvq-*,零硬编码。浮层显式声明 font-size / line-height(防主题放大正文),内容区用 .pvq-popover .pvq-popover__body(0,2,0)压过主题 .entry-content p(0,1,1)且不引用主题类。
  • API:PVQUI.popover(anchor, options) → 实例 { el, anchor, open(), close(), toggle(), destroy() }。options:
字段 类型 默认 说明
content string | Element — 字符串按 HTML 插入(调用方须自行确保可信,不得拼未转义的用户输入);传 DOM 节点则直接挂载
target Element — 既有 .pvq-popover 元素;不传则由库创建并挂到 <body>(destroy() 时一并移除)
placement string 'auto' auto(自动翻转)/ below / above
gap number 8 与锚点的间距(px)
closeDelay number 160 鼠标移开后延时关闭(ms),给移入浮层留时间
role string 'note' 库创建浮层时写入的 role
onOpen / onClose function — 回调,入参为实例
  • 行为:桌面 mouseenter / mouseleave(延迟 closeDelay 关闭);触屏(matchMedia('(hover: hover)') 判定,不信伪悬停)改为点按开合;锚点 focusin / focusout 键盘可达;Escape 关闭并把焦点交还锚点;点击浮层与锚点之外关闭;关闭有退出过渡(180ms,与 CSS .18s 对齐)不掐断动画;锚点滚动(捕获阶段监听,含任意滚动容器)与窗口缩放时打开态重新定位;prefers-reduced-motion 下无过渡与位移。

  • 事件(均冒泡):pvq-popover:open / pvq-popover:close,detail: { popover, el, anchor, reason }(reason 为 pointer / focus / click / escape / outside / api)。

  • 可访问性:浮层 role="note"(不用 tooltip——tooltip 语义要求「纯说明文本、不含可交互内容」,而本组件允许浮层内含链接等富内容);锚点 tabindex="0" + aria-describedby="<浮层 id>"(库仅在缺失时补写、不覆盖既有值);组件不是模态,不做焦点陷阱与 aria-modal。

  • 声明式触发(便于后端渲染 / 官网 demo):锚点加 data-pvq-popover="<浮层 id>" 即由 initPopovers() 接管(值为空时回退读 aria-describedby);目标必须存在且带 .pvq-popover 类,以免误绑普通 aria-describedby 说明文本。声明式走默认参数,要定制用命令式。

  • 幂等提醒:initAll() 同时绑定在 DOMContentLoaded 与 window resize 上,故同一浮层只初始化一次(实例挂 el.__pvqPopover),document/window 级监听(Escape / 外部点击 / scroll / resize)只绑一次(模块级 popoverGlobalBound)。

  • 已知边界:祖先带 transform / filter / backdrop-filter / will-change 会成为 position:fixed 的包含块而致坐标偏移——库不移动浮层 DOM(最小侵入),这类容器里须把浮层放到该容器之外。

  • 无 JS 边界:库默认即浮层态(不设 .pvq-js 渐进分支),故 JS 缺席时浮层保持不可见;信息兜底由调用方提供(如 <noscript> 静态呈现)。

  • 明确不做:业务内容槽(__title / __icon 等)、异步加载、自动消失计时、拖拽吸附、多层嵌套、position:absolute 定位模式。

  • 完整落库决策见 doc/开发文档/PVQ-UI回流落库-Popover锚点浮层.md。

  • 示例(声明式):

    <button type="button" tabindex="0" class="pvq-btn pvq-btn--ghost"
            data-pvq-popover="pvq-demo-pop" aria-describedby="pvq-demo-pop">悬停 / 点按我</button>
    
    <div class="pvq-popover" id="pvq-demo-pop" role="note" hidden>
      <div class="pvq-popover__body"><p>以元素为锚、脱离文档流、按需显隐的浮层。</p></div>
      <div class="pvq-popover__foot">术语解释 · 悬停查看</div>
      <span class="pvq-popover__arrow"></span>
    </div>

统计 Stat(原 cache-stat)· stable

  • 类:.pvq-stat-grid .pvq-stat .pvq-stat__value .pvq-stat__label
  • 示例:
    <div class="pvq-stat-grid">
      <div class="pvq-stat"><div class="pvq-stat__value">128</div><div class="pvq-stat__label">已同步</div></div>
      <div class="pvq-stat"><div class="pvq-stat__value">12</div><div class="pvq-stat__label">待处理</div></div>
    </div>

帮助 Help(原 help-card)· stable

  • 类:.pvq-help .pvq-help__icon .pvq-help__title .pvq-help__text
  • 示例:
    <div class="pvq-help">
      <i class="pvq-help__icon fas fa-lightbulb"></i>
      <div><div class="pvq-help__title">小贴士</div><div class="pvq-help__text">首次使用请先配置 Token。</div></div>
    </div>

范围 Range · stable(v1.2.10 增强:数值框可编辑)

  • 类:.pvq-range__group input.pvq-range .pvq-range__value .pvq-range__labels

  • .pvq-range__value 双形态(渐进增强,向后兼容):

    • **<span>/.pvq-range__value**:只读显示(旧行为,拖动滑块由库 JS 写入 textContent)。
    • **<input type="number" class="pvq-range__value">:可直接输入数字**,失焦/回车/步进即回写滑块值;非法或超范围自动 clamp 到 min/max 并按 step 对齐。
  • JS 行为(双向实时联动,二者互不失效):

    • 拖滑块 → 数值框:滑块 input 事件写回框内。<input> 写 .value、<span> 写 .textContent——注意:对 <input> 必须写 .value,textContent 对 void element 无效,曾导致「拖滑块不更新输入框」的 bug(v1.2.10 修复)。
    • 数值框编辑 → 滑块:输入过程中(input 事件)实时 clamp + step 对齐并更新滑块,但不改写框内文本(否则输入 50 时输完 5 就被改写、光标跳位);回车/步进器(change)与失焦(focusout)时才校正框内显示为合法值。内部用 rangeSyncing 标志避免派发事件回写打断输入。
    • 回写滑块后对滑块派发原生 input/change,插件原有监听无需改动。字段识别靠 .pvq-range__value 的 tagName,无需额外属性或初始化。
  • CSS:input.pvq-range__value 继承原只读框视觉(绿底 --pvq-primary-light、绿字、圆角 sm),并隐藏 number spinner(appearance:textfield + ::-webkit-*-spin-button 置 none),focus 加 border-color: var(--pvq-primary) + --pvq-primary-glow 辉光,宽度 min-width:80px(可由插件覆)。

  • 示例(只读 / 可编辑 两种写法):

    <!-- 只读(原有写法,仍受支持) -->
    <div class="pvq-range__group">
      <input type="range" class="pvq-range" min="1" max="100" value="50">
      <span class="pvq-range__value">50</span>
    </div>
    <div class="pvq-range__labels"><span>慢</span><span>快</span></div>
    
    <!-- 可编辑(v1.2.10 新增:数值框直接改,回写滑块) -->
    <div class="pvq-range__group">
      <input type="range" class="pvq-range" min="1" max="100" value="50">
      <input type="number" class="pvq-range__value" min="1" max="100" step="1" value="50"
             aria-label="数值">
    </div>
    <div class="pvq-range__labels"><span>慢</span><span>快</span></div>

二次确认弹窗 Confirm Modal · stable(v1.2.10 新增)

  • 类:.pvq-modal[data-pvq-modal] .pvq-modal--open --busy --warning --primary;子元素 .pvq-modal__backdrop .pvq-modal__panel __close __icon __title __desc __list __actions __cancel __confirm __spinner。

  • 用途:破坏性 / 重要操作的弹窗式二次确认。与既有 data-pvq-confirm(按钮就地二次确认,1.2.0)互为补充、不冲突:就地确认适合表格行内删除等轻量场景,弹窗适合需要说明后果、列出影响对象、异步执行的重量级场景。

  • 设计原则:形状归库、颜色归令牌。组件仅定义 --pvq-modal-accent(默认 var(--pvq-danger) 红,与库 --armed 二次确认态语义一致)与 --pvq-modal-accent-light、--pvq-modal-radius(默认 24px);图标圆、清单圆点、确认按钮(含 hover 与投影)全部走 accent,零硬编码色值。变体 --warning(黄)/ --primary(森林绿)只换令牌,形状与结构不变。

  • 结构契约:.pvq-modal 为 position:fixed 全屏遮罩容器(默认 display:none,加 --open 才显形),内部依次为 .pvq-modal__backdrop(点击关闭)+ .pvq-modal__panel(role="dialog" aria-modal="true")→ 图标 __icon → 标题 __title → 描述 __desc → 可选清单 __list → 按钮组 __actions(__cancel + __confirm,flex:1 1 0 等宽)。

  • 按钮实色 + 高特度(关键坑):确认按钮为实色 accent + 白字,用于「一眼识别动作性质」。因库基础样式是 button.pvq-btn.pvq-btn(0,3,1)且 background: var(--pvq-surface),组件按钮必须写到 (0,4,1)(button.pvq-btn.pvq-modal__confirm.pvq-modal__confirm)才能压过,否则只看到彩色阴影、按钮本体是白的。取消按钮同理;hover 的 color、:disabled 的 opacity、点击涟漪 ::before 也需同特度接管。

  • JS 入口:window.PVQUI.initConfirms()(initAll() 自动调用,幂等):

    • 触发器 [data-pvq-modal-open="<弹窗id>"] → 打开对应 .pvq-modal;
    • [data-pvq-modal-close](右上角 X / 取消按钮 / 遮罩)→ 关闭;
    • [data-pvq-modal-confirm] → 派发 pvq-modal:confirm(detail:{ id, modal, trigger })后关闭。插件监听该事件执行真实操作(删除请求等),库只管 UI 不碰业务。
    • 派发 pvq-modal:open / pvq-modal:close。
    • 异步场景:给确认按钮加 [data-pvq-modal-async],点击后按钮转 spinner + 禁用(防重复提交),由插件在业务完成后调用 modal.closeModal() 关闭;库不自动关闭。
  • 无障碍:role="dialog" + aria-modal + aria-labelledby;打开时默认聚焦取消按钮(防回车误触发破坏性操作);焦点陷阱(Tab/Shift+Tab 锁在弹窗内);Esc 关闭;关闭后焦点归还触发元素;滚动锁定(库在 <html> 上加 .pvq-scroll-locked,关闭与 pagehide 时释放,bfcache 恢复时自愈复位)。尊重 prefers-reduced-motion。

  • 窄屏(≤480px)转贴底抽屉,按钮组 column-reverse(确认在上、更易点到)。

  • 示例(最小结构):

    <button class="pvq-btn pvq-btn--danger" data-pvq-modal-open="del-modal">删除</button>
    
    <div class="pvq-modal" id="del-modal" data-pvq-modal role="dialog" aria-modal="true" aria-labelledby="del-t">
      <div class="pvq-modal__backdrop" data-pvq-modal-close></div>
      <div class="pvq-modal__panel">
        <button class="pvq-modal__close" data-pvq-modal-close aria-label="关闭">✕</button>
        <div class="pvq-modal__icon"><i class="fas fa-triangle-exclamation"></i></div>
        <h3 class="pvq-modal__title" id="del-t">确认删除?</h3>
        <p class="pvq-modal__desc">此操作将永久删除 <strong>“项目报告 Q3”</strong>,且<strong>无法恢复</strong>。</p>
        <div class="pvq-modal__actions">
          <button type="button" class="pvq-btn pvq-modal__cancel" data-pvq-modal-close>取消</button>
          <button type="button" class="pvq-btn pvq-modal__confirm" data-pvq-modal-confirm>确认删除</button>
        </div>
      </div>
    </div>
    // 插件接业务:
    document.addEventListener('pvq-modal:confirm', function (e) {
      if (e.detail.id !== 'del-modal') return;
      // …执行删除请求;异步场景用 data-pvq-modal-async + e.detail.modal.closeModal()
    });

分隔 Divider · stable

  • 类:.pvq-divider

可折叠卡片 Collapse · experimental【新增】

  • 结构:.pvq-collapse > button.pvq-collapse__header[aria-expanded] + .pvq-collapse__body > .pvq-collapse__inner
  • 箭头:<i class="fa-solid fa-chevron-down pvq-collapse__arrow"></i>(FontAwesome),展开态旋转 180° 变主色
  • 标题:浅灰底(--pvq-surface-alt),展开时底边加阴影分隔
  • 内边距:.pvq-collapse__inner 为 padding: 16px 18px(顶部/底部 16px、左右 18px 与 header 对齐),展开后内容与 header 间距充足、不发挤(原顶部 12px 偏紧)
  • 行为:点击标题切换 --open 类名;aria-expanded 同步更新;展开态 JS 将 body.style.maxHeight 设为 'none'(非 scrollHeight+'px'),收起/展开过渡临时用 px、transitionend(仅 max-height 属性)后回到 'none',保证高度动画平滑且内容异步变高不被固定 px 裁切
  • 隐藏容器兼容:卡片位于 display:none 选项卡内时,加载期 scrollHeight 量出 0 不再导致「假收起 / 点一下没反应」(v1.2.7 修复;原逻辑写死 scrollHeight+'px' 导致默认展开却显示收起)
  • 默认展开:.pvq-collapse 上加 .pvq-collapse--open,JS 自动校准 max-height 为 'none'
  • 多卡片可同时展开(非手风琴),互不影响
  • JS 入口:window.PVQUI.initCollapses()(initAll() 自动调用)
  • 示例:
    <div class="pvq-collapse" data-pvq-collapse>
      <button class="pvq-collapse__header" aria-expanded="false">
        <span>标题文本</span>
        <i class="fa-solid fa-chevron-down pvq-collapse__arrow"></i>
      </button>
      <div class="pvq-collapse__body">
        <div class="pvq-collapse__inner">内容...</div>
      </div>
    </div>

点击上传 Upload · experimental【新增】

  • 结构:.pvq-upload > input[type="file"].pvq-upload__input(隐藏) + button.pvq-upload__trigger + .pvq-upload__info > .pvq-upload__name + button.pvq-upload__clear
  • 行为:点击触发区 → 打开文件选择 → 选中后在下方显示文件名 + ✕ 清除按钮
  • 布局变体:默认 column(trigger 在上、info 在下);加 --inline 改为 row(align-items: center),整行回到单行高度,用于 WP 设置行与相邻行对齐。
  • 清除按钮语义色:.pvq-upload__clear(✕)默认 color: var(--pvq-text-muted)、background: transparent(静音、退居次要,不与整行绿色糊在一起);hover / :focus-visible 转为危险红 color: var(--pvq-danger) + background: var(--pvq-danger-light),键盘聚焦同款 outline: 2px solid var(--pvq-danger)。危险色仅在「意图发生那一刻」(hover/聚焦)出现,避免整行常驻红色告警;复用库 --pvq-danger / --pvq-danger-light(与 banner/status/alert 一致)。
  • 变体:.pvq-upload--solid(实色按钮)、.pvq-upload--drop(大号拖放区风格)、.pvq-upload--inline(横排:trigger 与 info 同一行,适配设置行等高对齐;与 --solid 可叠加;不与 --drop 同用)
  • JS 入口:window.PVQUI.initUploads()(initAll() 自动调用),幂等初始化
  • 示例:
    <div class="pvq-upload" data-pvq-upload>
      <input type="file" class="pvq-upload__input">
      <button type="button" class="pvq-upload__trigger"><i class="fa-solid fa-cloud-arrow-up"></i> 选择文件</button>
      <div class="pvq-upload__info">
        <span class="pvq-upload__name"><i class="fa-solid fa-file"></i> <span class="pvq-upload__name-text"></span></span>
        <button type="button" class="pvq-upload__clear"><i class="fa-solid fa-times"></i></button>
      </div>
    </div>

搜索组件 Search · stable(base 层,1.2.8 新增)

  • 类:.pvq-search;结构:<i class="pvq-search__icon fas fa-magnifying-glass">(放大镜图标,绝对定位)+ <input class="pvq-search__input">(内部 input,特异性 input.pvq-search__input(0,2,1)压过 WP 核心)+ 可选 <button class="pvq-search__clear">(清除 ✕,JS 控制显隐)+ 可选 <button class="pvq-search__submit">(提交,joined 右段)+ 可选 <i class="pvq-search__spinner fas fa-spinner fa-spin">(加载态 spinner)。

  • 设计原则:形状归库、颜色归令牌。组件定义 --pvq-search-accent(默认 var(--pvq-primary) 绿),focus 边框/辉光/提交按钮底色全走它;hover 用 color-mix(in srgb, accent 82%, #000) 压暗(任意色可用,零硬编码)。库不内置 off-brand 色(蓝/橙由插件自覆盖 --pvq-search-accent)。

  • 功能变体(结构/行为):

    • --with-btn:右侧实心「搜索」按钮(joined 段,自带左分隔线),点击或回车提交。
    • --with-filter:左侧复用库 .pvq-select 作范围段(标题/正文/作者…),与全站 Select 视觉一致;库 JS 自动增强(触发器 + body 级下拉),改选即带范围重搜。覆盖 .pvq-select 自身边框/圆角/辉光、仅留右侧分隔线,外层容器 :focus-within 统一承担辉光避免「双辉光」。示例里给该 select 加的 .pvq-search__filter 是语义钩子(自身无 CSS 规则),实际样式由后代选择器 .pvq-search--with-filter .pvq-select 提供;不写该钩子也能正常工作。 几何契约(v1.4.1 修正,勿再踩):筛选段是 flex:none; width:110px 的流内 flex 子项(不是绝对定位),故 <input>(flex:1)自身左缘已在容器 110px 处。据此:图标用容器坐标 left:124px(= 110 段宽 + 14 间隙);输入框 padding-left 必须用 input 自身坐标 取 40px(= 150 − 110),文字才落在容器 150px(图标右缘 138 + 12 间隙)。切勿写成 150px —— 那会让文字落到 260px、比预期多出整整一个段宽(1.2.8 ~ 1.4.0 的缺陷即此)。 若将来要几何令牌化,正确形式是 padding-left: calc( var(--pvq-search-text-x, 150px) - var(--pvq-search-filter-w, 110px) ) —— 要减段宽,因为图标用容器坐标、padding 用元素自身坐标,两者坐标系不同;这一步属新增令牌 = MINOR,未纳入 1.4.1(PATCH)。
    • --loading:图标位转 spinner(.pvq-search--loading .pvq-search__spinner 显示);插件在异步检索期间自行加/去该类。
    • --sm:紧凑高度 34px(图标/缩进同步缩小),用于表格工具条等密集区。
  • 形状变体(新增 4 个):--pill(全圆角,已有圆角语义)、--underline(无框仅底线,极简克制)、--ghost(填底无边框,聚焦加环)、--glass(半透明 + backdrop-filter: blur,前端装饰,需彩色背板才能看到 blur)。

  • 暗色不是变体:暗色由库 --pvq-surface/--pvq-text/--pvq-border/--pvq-primary 令牌主题切换,.pvq-search 自动适配,不新增暗色修饰符。

  • JS(库自动初始化,initSearches(),initAll 自动调用,幂等):清除按钮显隐/清空;提交(按钮点击或回车,回车 preventDefault)与筛选 change(仅当有词)派发 pvq-search CustomEvent(bubbles,detail: { query, filter, element }),插件监听该事件执行真实检索(库不假设后端)。加载态由插件控制。

  • 示例(默认 / 带按钮 / 形状 / 毛玻璃 / 筛选 / 小号+加载 / 蓝橙 accent):

    <!-- 默认填框 + 清除 -->
    <div class="pvq-search" data-pvq-search>
      <i class="pvq-search__icon fas fa-magnifying-glass"></i>
      <input class="pvq-search__input" type="text" placeholder="搜索文章、用户、标签…">
      <button class="pvq-search__clear" type="button" aria-label="清除"><i class="fas fa-xmark"></i></button>
    </div>
    
    <!-- 带提交按钮 -->
    <div class="pvq-search pvq-search--with-btn" data-pvq-search>
      <i class="pvq-search__icon fas fa-magnifying-glass"></i>
      <input class="pvq-search__input" type="text" placeholder="输入关键词后点搜索">
      <button class="pvq-search__submit" type="button"><i class="fas fa-magnifying-glass"></i> 搜索</button>
    </div>
    
    <!-- 筛选前置(复用库 .pvq-select) -->
    <div class="pvq-search pvq-search--with-filter" data-pvq-search>
      <div class="pvq-select pvq-search__filter">
        <select name="pvq_search_scope">
          <option>全部</option><option>标题</option><option>正文</option><option>作者</option>
        </select>
      </div>
      <i class="pvq-search__icon fas fa-magnifying-glass"></i>
      <input class="pvq-search__input" type="text" placeholder="在所选范围内搜索…">
    </div>
    
    <!-- 蓝/橙强调:仅覆盖令牌,形状不变 -->
    <div class="pvq-search pvq-search--with-btn" data-pvq-search style="--pvq-search-accent:#2563eb">
      <i class="pvq-search__icon fas fa-magnifying-glass"></i>
      <input class="pvq-search__input" type="text" placeholder="蓝色主题搜索…">
      <button class="pvq-search__submit" type="button"><i class="fas fa-magnifying-glass"></i> 搜索</button>
    </div>
  • 插件监听检索事件:

    document.addEventListener('pvq-search', function (e) {
      var q = e.detail.query, scope = e.detail.filter;
      // 调用真实检索接口…
    });

颜色输入框 ColorField · experimental【新增】

  • 结构:.pvq-color-field > .pvq-color-field__swatch + input.pvq-color-field__input(CSS 选择器写成 .pvq-color-field input.pvq-color-field__input 以抬升特异度压过 WP 核心;HTML class 不变)
  • 行为:点击色块弹出全局共享自绘取色面板(饱和度/亮度 Canvas + 色相条 + hex 输入),圆头鼠标指示器;手动输入 hex 双向同步色块
  • 取色面板通过 position: fixed 挂 <body>(全局唯一,所有 ColorField 共享),点击外部或按确定/Enter 关闭并应用
  • 变体:.pvq-color-field--sm(小号)
  • JS 入口:window.PVQUI.initColorFields()(initAll() 自动调用,仅建一次共享面板)
  • 示例:
    <div class="pvq-color-field" data-pvq-color-field>
      <div class="pvq-color-field__swatch" data-hex="#608062" style="background:#608062"></div>
      <input type="text" class="pvq-color-field__input" value="#608062" maxlength="7">
    </div>

转圈 Spinner · stable

  • 类:.pvq-spinner;动画 @keyframes pvq-spin

元信息列表 Meta-list(原 system-info)· stable

  • 类:.pvq-meta-list .pvq-meta-list__row .pvq-meta-list__key .pvq-meta-list__value .pvq-meta-list__value--{ok,bad}

    .pvq-meta-list__value 与 .pvq-meta-list__key 同排继承 .pvq-meta-list 的字号/颜色,自身无独立 CSS 规则(纯扩展钩子);着色由修饰符 --ok(绿)/--bad(红)提供。

  • 示例:
    <div class="pvq-meta-list">
      <div class="pvq-meta-list__row"><span class="pvq-meta-list__key">PHP</span><span class="pvq-meta-list__value pvq-meta-list__value--ok">8.1</span></div>
    </div>

动画 Animations · stable

  • @keyframes pvq-spin(转圈)、pvq-pulse(状态点)、pvq-shimmer(光泽)、pvq-slideDown/Up、pvq-cardEnter、pvq-tabEnter、pvq-iconBounce、pvq-badgePulse、pvq-resultSlide、pvq-logoAppear、pvq-lightbulb、pvq-detectBarEnter
  • base 层另含 @media (prefers-reduced-motion: reduce) 全局降级。

3.2 Admin 层(pvq-ui-admin.css)

设置页骨架 Settings · stable

  • 类:.pvq-settings .pvq-settings__header .pvq-settings__logo .pvq-settings__title-group .pvq-settings__title .pvq-settings__subtitle .pvq-settings__version-badge .pvq-settings__footer .pvq-settings__footer-info .pvq-settings__footer-links .pvq-settings__footer-link .pvq-settings__footer-link--disabled

选项卡 + 磁吸滑块 Tabs · stable

  • 类:.pvq-tabs .pvq-tabs__slider .pvq-tab .pvq-tab--active .pvq-tab__icon .pvq-tab-content .pvq-tab-content--active
  • 交互:库 JS 委托点击切换 + 移动滑块(见《调用手册》§5)。
  • 形态:分段控件式胶囊(pill)。容器 .pvq-tabs、磁吸滑块 .pvq-tabs__slider、tab .pvq-tab 均为全圆角(--pvq-radius-pill: 999px);容器 width: fit-content 紧凑跟随内容(不撑满整行)、1px --pvq-border-light 淡边框(与 pvq-wp 一致);激活态靠滑块主色渐变垫底、文字白,未激活灰字、hover 浅主色底。JS 仅按 offsetLeft/offsetWidth 定位滑块,圆角变化不影响逻辑。参考 pvq-wp 选项卡实现(1.1.1 起由矩形圆角改为胶囊,1.1.2 起边框对齐 pvq-wp 淡边框)。
  • 示例:
    <div class="pvq-tabs">
      <span class="pvq-tabs__slider"></span>
      <button class="pvq-tab pvq-tab--active" data-pvq-tab="general"><i class="pvq-tab__icon fas fa-cog"></i> 常规</button>
      <button class="pvq-tab" data-pvq-tab="advanced"><i class="pvq-tab__icon fas fa-sliders-h"></i> 高级</button>
    </div>
    <div class="pvq-tab-content pvq-tab-content--active" data-pvq-tab-panel="general">…</div>
    <div class="pvq-tab-content" data-pvq-tab-panel="advanced">…</div>

范围 Range · stable(见 §3.1,admin 设置页常用,随 admin 层提供)


3.3 Editor 层(pvq-ui-editor.css)

块骨架 Block · stable

  • 类:.pvq-block-placeholder .pvq-block-loading .pvq-block-empty .pvq-block-preview .pvq-block-frame
  • 说明:通用块编辑占位 / 加载 / 空态 / 预览 / 边框,供各插件块复用。

3.4 Frontend 层(pvq-ui-frontend.css)

内容组件 · stable

  • 类:.pvq-callout .pvq-callout__icon .pvq-callout__content .pvq-quote .pvq-prose
  • 说明:前端通用内容展示(提示框 / 引用 / 正文排版)。

进度条 Progress · stable(1.2.9 并入)

  • 类:.pvq-progress .pvq-progress__fill .pvq-progress__text;变体 .pvq-progress--lg(大号)、.pvq-progress--danger(危险红,走 --pvq-danger)。
  • 令牌:--pvq-progress-accent(默认 --pvq-primary 绿,危险态覆盖为 --pvq-danger),零硬编码。
  • 纯 CSS,进度由 JS 设置 .pvq-progress__fill 的 width。
  • 示例:
    <div class="pvq-progress"><div class="pvq-progress__fill" style="width:35%"></div><span class="pvq-progress__text">35%</span></div>
    <div class="pvq-progress pvq-progress--danger"><div class="pvq-progress__fill" style="width:88%"></div><span class="pvq-progress__text">88% 风险</span></div>

书签 Bookmark · stable(1.2.9 并入)

  • 类:.pvq-bookmark .pvq-bookmark__image .pvq-bookmark__content .pvq-bookmark__url .pvq-bookmark__favicon .pvq-bookmark__title .pvq-bookmark__description
  • 结构:左图(.pvq-bookmark__image)右文(url + 标题 + 描述);去掉 __image 即纯文字链接卡。hover 浅绿底 + 稍深边框(--pvq-border-strong)。
  • 示例:
    <a class="pvq-bookmark" href="https://pvq.ink"><div class="pvq-bookmark__image" style="background-image:url(...)"></div><div class="pvq-bookmark__content"><div class="pvq-bookmark__url"><img class="pvq-bookmark__favicon" src="...">pvq.ink</div><div class="pvq-bookmark__title">PVQ 组件库官网</div><div class="pvq-bookmark__description">统一全站界面样式的跨插件组件库。</div></div></a>

卡片化表格 Table · stable(1.2.9 并入)

  • 类:.pvq-table(配合 .pvq-table-wrap 可加 [data-pvq-table] 触发入场动画);子结构即原生 table/thead/tbody/tr/th/td,可选 caption。
  • 默认观感:单元格独立圆角卡片、彼此留 0.3em 间隙(border-collapse:separate);表头绿底(--pvq-table-head-bg)、单元格淡绿底(--pvq-table-cell-bg);悬停高亮 + 微放大(scale(1.01) + 阴影)。
  • 修饰符:--striped(斑马纹,偶数行整行单元格换深一档绿底 --pvq-table-stripe-bg);列级对齐 __col--right / __col--center。整表对齐/边框/紧凑等变体在卡片语境下不成立(已不提供)。
  • 令牌(定义在 .pvq-table,零硬编码):--pvq-table-radius / --pvq-table-head-bg / --pvq-table-head-bg-hover / --pvq-table-cell-bg / --pvq-table-cell-bg-hover / --pvq-table-stripe-bg,均派生自 --pvq-primary / --pvq-radius-md。
  • 入场动画:.pvq-table-wrap[data-pvq-table] 由库 JS initTables() 经 IntersectionObserver 触发(pvq-is-visible);普通 .pvq-table 不加 data-pvq-table 则完全可见、无入场。
  • 示例:
    <div class="pvq-table-wrap" data-pvq-table><table class="pvq-table"><caption>语言速览</caption><thead><tr><th>语言</th><th class="pvq-table__col--right">诞生年</th></tr></thead><tbody><tr><td>PHP</td><td class="pvq-table__col--right">1995</td></tr></tbody></table></div>
    <!-- 斑马纹:<table class="pvq-table pvq-table--striped"> -->

权重输入框 Weight · stable(v1.2.10 新增,随 1.2.11 固化发布)

  • 类:.pvq-weight .pvq-weight__list .pvq-weight__item .pvq-weight__label .pvq-weight__badge .pvq-weight__input-wrap .pvq-weight__input(数字 input[type="number"],CSS 写 input.pvq-weight__input,0,2,1 压过 WP 核心).pvq-weight__unit(单位 %/后缀).pvq-weight__slider-wrap .pvq-weight__slider(滑块 input[type="range"],CSS 写 input.pvq-weight__slider,0,2,1).pvq-weight__action(底部操作区).pvq-weight__total(总和显示).pvq-weight__total-val。
  • 用途:多维权重配置(功能 / 性能 / 美观…),数字输入框 + 滑块双向联动微调,底部「重置 / 归一化」按钮使总和归 100;总和实时显示。
  • 设计原则:形状归库、颜色归令牌。组件定义 --pvq-weight-accent(默认 var(--pvq-primary) 绿),聚焦边框/辉光/滑块主色/单位底全走它;hover 用 color-mix(in srgb, accent 45%, #fff) 压浅,零硬编码。主按钮复用库 .pvq-btn--primary(绿渐变 + hover),重置复用 .pvq-btn--ghost,胶囊外形由 .pvq-weight__btn-pill 覆圆角(--pvq-radius-pill);组件本身不重定义按钮底色。
  • 结构契约:.pvq-weight__item 由 3 段横向排列(label / input-wrap / slider-wrap),flex-wrap 允许窄屏换行;.pvq-weight__input-wrap 为 position:relative,.pvq-weight__unit 绝对定位右侧(数字框 padding-right 让位)。JS 负责双向同步(输入→滑块、滑块→输入)与总和/归一化/重置逻辑——纯展示外壳归库,归一化算法由调用方可覆盖(监听 pvq-weight:normalize 事件,或仅用默认 window.PVQUI.initWeights())。
  • 令牌:--pvq-weight-accent(默认主色)、--pvq-weight-item-bg(卡片行底 var(--pvq-surface-hover))、--pvq-weight-item-hover(hover 浅主色底),全部派生自 --pvq-primary;不新增基础令牌(复用既有 --pvq-border-strong / --pvq-primary-glow / --pvq-radius-pill)。
  • 变体:.pvq-weight--sm(紧凑行高)、.pvq-weight--glass(半透明 + backdrop-filter 玻璃拟态,需彩色背板才显 blur)。
  • JS 入口:window.PVQUI.initWeights()(initAll() 自动调用,幂等):扫描 [data-pvq-weight],对每行数字框/滑块做双向同步 + 实时总和;绑定「归一化」「重置」按钮(按钮须带 data-pvq-weight-normalize / data-pvq-weight-reset);归一化后派发 pvq-weight:normalized 事件供插件接后端持久化。
  • 示例(最小结构):
    <div class="pvq-weight" data-pvq-weight>
      <div class="pvq-weight__list">
        <div class="pvq-weight__item">
          <span class="pvq-weight__label">功能 <span class="pvq-weight__badge">w1</span></span>
          <div class="pvq-weight__input-wrap">
            <input class="pvq-weight__input" type="number" min="0" max="999" step="0.1" value="35" aria-label="功能 权重">
            <span class="pvq-weight__unit">%</span>
          </div>
          <div class="pvq-weight__slider-wrap">
            <input class="pvq-weight__slider" type="range" min="0" max="100" step="0.5" value="35" aria-label="功能 滑块">
          </div>
        </div>
      </div>
      <div class="pvq-weight__action">
        <span class="pvq-weight__total">∑ 总和 <span class="pvq-weight__total-val">100.0</span></span>
        <div class="pvq-btn-group">
          <button type="button" class="pvq-btn pvq-btn--ghost pvq-weight__btn-pill" data-pvq-weight-reset>↺ 重置</button>
          <button type="button" class="pvq-btn pvq-btn--primary pvq-weight__btn-pill" data-pvq-weight-normalize>⟳ 归一化</button>
        </div>
      </div>
    </div>

数据表格 DataGrid · stable(1.2.9 并入,含 JS 交互)

  • 结构:.pvq-datagrid[data-pvq-datagrid] > .pvq-datagrid__toolbar(搜索/排序/筛选/重置按钮)+ .pvq-datagrid__content > .pvq-datagrid__table(同卡片化表格)+ .pvq-datagrid__empty(无结果提示)。
  • 工具栏:① 搜索 .pvq-datagrid__search(自包含胶囊:折叠为圆图标,点图标原地展开成输入框,点击栏外空白收起);② 排序 .pvq-datagrid__btn--sort(点头列或按钮三态循环 无/升/降);③ 筛选 .pvq-datagrid__filter(自包含胶囊:展开为「列 + 值」双自绘下拉多选,点击栏外空白收起);④ 重置 .pvq-datagrid__btn--reset(旋转图标,清空搜索/筛选/排序)。
  • 交互(库 JS initDataGrids(),initAll 自动调用,幂等):搜索实时过滤行、排序重排、筛选按列+值多选、重置恢复;入场动画同上([data-pvq-datagrid] 触发)。
  • 表头排序图标:.pvq-sort-icon(升 ↑ / 降 ↓ 由 .pvq-sort-asc/desc 控制)。该载体由库 JS 在 initSort 时自动注入每个表头(缺失才补),标记中可省略;默认态显示中性上下箭头 ↕,悬停/升/降态高亮。隐藏行类 .pvq-search-hidden / .pvq-filter-hidden。
  • 尺寸/令牌:复用 Table 的 --pvq-table-* 令牌;工具栏按钮 .pvq-datagrid__btn 圆角胶囊(白底 --pvq-surface,hover 浅灰 --pvq-surface-hover)。激活态 .pvq-datagrid__btn--active 绿底白字(--pvq-primary);:hover/:focus-visible 必须用 --pvq-primary-hover 保持绿系(与全库主按钮 hover 一致)——否则 .pvq-datagrid__btn:hover(特异性 0,1,1)的浅灰背景会盖掉 --active 绿底(0,1,0),激活态图标 color:#fff 落在浅灰底上不可见(视觉「白→白→黑」三态跳变)。v1.2.9 修正。**
  • 筛选下拉菜单由库 JS 依据表头(th[data-col])与单元格值自动生成,无需手写 <option>。
  • 示例(最小结构):
    <div class="pvq-datagrid" data-pvq-datagrid>
      <div class="pvq-datagrid__toolbar">
        <div class="pvq-datagrid__search"><button class="pvq-datagrid__toggle pvq-datagrid__toggle--search" type="button"><i class="fas fa-magnifying-glass"></i></button><input class="pvq-datagrid__search-input" type="text" placeholder="搜索…"><button class="pvq-datagrid__search-clear" type="button"><i class="fas fa-xmark"></i></button></div>
        <button class="pvq-datagrid__btn pvq-datagrid__btn--sort" type="button"><i class="fa-solid fa-up-down"></i></button>
        <div class="pvq-datagrid__filter"><button class="pvq-datagrid__toggle pvq-datagrid__toggle--filter" type="button"><i class="fas fa-filter"></i></button><div class="pvq-dd" data-pvq-dd="col"><button class="pvq-dd__trigger" type="button"><span class="pvq-dd__text">选择列</span><i class="pvq-dd__arrow fas fa-chevron-down"></i></button><div class="pvq-dd__menu"></div></div><div class="pvq-dd" data-pvq-dd="val"><button class="pvq-dd__trigger" type="button"><span class="pvq-dd__text">选择值</span><i class="pvq-dd__arrow fas fa-chevron-down"></i></button><div class="pvq-dd__menu"></div></div></div>
        <button class="pvq-datagrid__btn pvq-datagrid__btn--reset" type="button"><i class="fas fa-rotate-left"></i></button>
      </div>
      <div class="pvq-datagrid__content"><table class="pvq-datagrid__table"><thead><tr><th data-col="项目">项目<i class="pvq-sort-icon"></i></th></tr></thead><tbody><tr><td>示例</td></tr></tbody></table><div class="pvq-datagrid__empty">无匹配结果</div></div>
    </div>

4. 不在库内(留在插件自有)

以下强绑定各自数据模型 / 业务逻辑,不进库,但要求改用 --pvq-* 令牌保持一致风格:

  • wolai 专有:.pvq-wolai-*、.pvq-token-info、.pvq-detect-bar、.pvq-status-available/-unavailable、.pvq-wolai-callout 等。
  • 各插件业务逻辑专有样式,留在插件,不回流库。

5. 新增组件流程(库增量贡献)

  1. 先查本表确认不存在。
  2. 在 doc/开发文档/ 或本表写组件条目(API / 类 / 令牌 / 示例),先标 experimental。
  3. 写 CSS/JS(BEM 双横线、统一令牌、pvq- 动画前缀)。
  4. bump 版本(MINOR),按《PVQ-UI项目规则.md》§1.3 版本七处同步,并同步 CHANGELOG.md、readme.md 与 site/inc/components.json 的 version / stability。
  5. 经 1~2 个插件验证后,本表稳定性改为 stable。

详见《PVQ-UI项目规则.md》§1、§5、§8 与《库演进治理方案.md》§4。