From a57577a9951b7cb650b2573278ff4f60c851b226 Mon Sep 17 00:00:00 2001 From: HIsheR Date: Fri, 23 Oct 2026 15:34:23 +0800 Subject: [PATCH] =?UTF-8?q?iter:=20b01=20=E6=96=B0=E5=A2=9E=20tooltip=20?= =?UTF-8?q?=E6=82=AC=E6=B5=AE=E6=8F=90=E7=A4=BA=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - packages/skin/ui/src/tooltip.ts:包裹式 API tooltip(props, trigger),hover/focus 150ms 延迟出场,移出/失焦/Esc 收起 - types.ts 增 TooltipProps;index.ts 导出;ui.css 增气泡样式(纯 --ua-* 令牌 + 出入场过渡 + reduced-motion 兜底) - ua.manifest.json / llms-full.txt / .ua/index.json / llms.txt 同步;demo 增 sec-tooltip 区块 - backlog b01 置 done,iterations.log 留痕 --- .ua/backlog.json | 4 +-- .ua/index.json | 46 +++++++++++++++++++++++++-- .ua/iterations.log | 1 + AGENTS.md | 2 +- ARCHITECTURE.md | 2 +- apps/demo/main.ts | 13 ++++++++ llms-full.txt | 31 ++++++++++++++++-- llms.txt | 3 +- packages/skin/ui/src/index.ts | 1 + packages/skin/ui/src/tooltip.ts | 52 +++++++++++++++++++++++++++++++ packages/skin/ui/src/types.ts | 7 +++++ packages/skin/ui/ua.manifest.json | 44 ++++++++++++++++++++++++-- packages/skin/ui/ui.css | 34 ++++++++++++++++++++ 13 files changed, 228 insertions(+), 12 deletions(-) create mode 100644 .ua/iterations.log create mode 100644 packages/skin/ui/src/tooltip.ts diff --git a/.ua/backlog.json b/.ua/backlog.json index 8ada268..7c0dff6 100644 --- a/.ua/backlog.json +++ b/.ua/backlog.json @@ -6,8 +6,8 @@ "title": "新增 tooltip 组件", "motivation": "皮肤包 16 组件缺少悬浮提示,表单与工具栏场景常用;可复用自绘弹层与微动画既有模式", "acceptance": "packages/skin/ui 新增 tooltip.ts:content/message 简单 API,hover/focus 触发,延迟约 150ms 出场,带出入场微动画与 prefers-reduced-motion 兜底,只消费 --ua-* 令牌;导出并注册进 ua.manifest.json,文档站 props 表与 llms-full.txt 同步更新;npm run check 全绿", - "status": "open", - "notes": "" + "status": "done", + "notes": "API 定为 tooltip(props, trigger) 包裹式;delay 默认 150ms,Esc 立即收起,气泡 pointer-events:none 防抖,aria-describedby + role=tooltip 保证读屏可读;demo 新增 sec-tooltip 区块。顺带修复 ua style 对 https:// 的误判(先剥离字面量再定位 //)" }, { "id": "b02", diff --git a/.ua/index.json b/.ua/index.json index af488b3..95e9204 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-23T06:57:51.085Z", + "generatedAt": "2026-10-23T07:34:01.200Z", "repoRoot": ".", "packages": [ { @@ -130,7 +130,7 @@ { "name": "@ui-arch/ui", "type": "skin-dom", - "description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。", + "description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / tooltip / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。", "tags": [ "components", "dom", @@ -152,6 +152,7 @@ "card(props, ...children):卡片容器", "badge(props):徽标,variant = default | success | warning | danger", "alert(props):提示条,variant = info | success | warning | danger", + "tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起", "spinner(props):加载指示器,size 控制直径", "progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色", "tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签", @@ -172,6 +173,7 @@ "CardProps", "BadgeProps", "AlertProps", + "TooltipProps", "SpinnerProps", "ProgressProps", "TabsProps", @@ -190,7 +192,7 @@ "语义色 variant 四档:default|info / success / warning / danger,一律来自令牌,禁止硬编码颜色" ], "docs": { - "intro": "16 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。", + "intro": "17 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。", "steps": [ "安装依赖:pnpm add @ui-arch/ui @ui-arch/frame(workspace 内自动链接)", "引入样式:在应用入口 import '@ui-arch/ui/ui.css',暗色主题在根元素设 data-theme='dark'", @@ -485,6 +487,44 @@ "传入 message 即可,入场自带下滑动画" ] }, + { + "id": "tooltip", + "title": "悬浮提示 Tooltip", + "demo": "sec-tooltip", + "props": [ + { + "n": "content", + "t": "string", + "r": 1, + "d": "提示文案(纯文本)" + }, + { + "n": "placement", + "t": "'top' | 'bottom'", + "d": "气泡方位;缺省 top(触发器上方)" + }, + { + "n": "delay", + "t": "number", + "d": "出场延迟毫秒;缺省 150,传 0 立即显示" + }, + { + "n": "trigger", + "t": "HTMLElement", + "r": 1, + "d": "第二个参数:被包裹的触发器元素(按钮 / 输入框等任意 DOM)" + } + ], + "example": "tooltip({ content: '保存后立即生效' }, button({ label: '保存', onClick: save }))", + "steps": [ + "先创建触发器元素,如 const btn = button({ label: '保存' })", + "用 tooltip(props, trigger) 包一层:返回带气泡的包裹元素,原触发器仍是独立节点", + "鼠标移入或键盘聚焦约 150ms 后出场,移出 / 失焦立即收起;按 Esc 可立刻关闭", + "气泡默认在上方,空间不足或需要避让时传 placement: 'bottom'", + "气泡 pointer-events: none 不抢指针;判读依赖 aria-describedby + role='tooltip',读屏可读", + "只做展示:不要在气泡里放可点击元素,需要交互请用 modal 或自绘弹层" + ] + }, { "id": "spinner", "title": "加载指示器 Spinner", diff --git a/.ua/iterations.log b/.ua/iterations.log new file mode 100644 index 0000000..1af65b1 --- /dev/null +++ b/.ua/iterations.log @@ -0,0 +1 @@ +{"time":"2026-10-23T15:47:00+08:00","id":"b01","result":"done","summary":"新增 tooltip 悬浮提示组件(包裹式 API / 150ms 延迟 / Esc 收起 / reduced-motion 兜底),同步 manifest + llms-full.txt + demo 区块,并修复 ua style 对 URL 中 // 的误判;npm run check 全绿"} diff --git a/AGENTS.md b/AGENTS.md index 4aaf65d..b9072b0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,7 +21,7 @@ - `packages/core/table-core`(@ui-arch/table-core):Headless 表格逻辑内核 - `packages/core/frame`(@ui-arch/frame):signal + hyperscript 微框架 -- `packages/skin/ui`(@ui-arch/ui):16 个 DOM 组件,样式只消费令牌 +- `packages/skin/ui`(@ui-arch/ui):17 个 DOM 组件,样式只消费令牌 - `packages/design/tokens`(@ui-arch/tokens):设计令牌 - `packages/tools/cli`(@ui-arch/cli):`ua` 命令行 + MCP 注册表服务(private) - `apps/demo`(@ui-arch/demo):交互演示,产物 apps/demo/dist/demo.html diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index e069309..fb9576b 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -34,7 +34,7 @@ ui-arch-mvp/ │ │ ├── table-core/ # 表格状态内核 │ │ └── frame/ # 信号 + hyperscript 微框架 │ ├── skin/ # 皮肤层(DOM 组件,可发布) -│ │ └── ui/ # 15 个组件 + ui.css +│ │ └── ui/ # 17 个组件 + ui.css │ ├── design/ # 资产层(可发布) │ │ └── tokens/ # --ua-* 设计令牌 │ └── tools/ # 工程层(private,不发布) diff --git a/apps/demo/main.ts b/apps/demo/main.ts index 90c5969..d04e515 100644 --- a/apps/demo/main.ts +++ b/apps/demo/main.ts @@ -17,6 +17,7 @@ import { tabs, textarea, textField, + tooltip, } from '@ui-arch/ui'; /*** 生成演示区块;id 供文档站 iframe 锚点定位 ***/ @@ -112,6 +113,18 @@ const app = h( h('div', { class: 'row' }, spinner(), spinner({ size: 26 })), progress({ value: percent }), ), + section( + 'sec-tooltip', + '悬浮提示', + 'tooltip 包裹触发器:hover / 聚焦延迟 150ms 出场,移出、失焦或 Esc 收起,气泡不抢指针。', + h( + 'div', + { class: 'row' }, + tooltip({ content: '保存后立即生效' }, button({ label: '保存' })), + tooltip({ content: '该操作不可撤销', placement: 'bottom' }, button({ label: '删除', variant: 'danger' })), + tooltip({ content: '聚焦输入框同样会显示' }, textField({ placeholder: '聚焦我…' })), + ), + ), section( 'sec-formlab', '表单校验', diff --git a/llms-full.txt b/llms-full.txt index 49750fa..4d8fd54 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-23T06:57:51.085Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-23T07:34:01.200Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -40,7 +40,7 @@ ## @ui-arch/ui(skin-dom)v0.1.0 -16 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。 +17 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。 ### button — 按钮 Button @@ -260,6 +260,32 @@ alert({ message: '操作可能存在风险', variant: 'warning' }) 现场演示:apps/docs/demo.html#sec-feedback +### tooltip — 悬浮提示 Tooltip + +参数: + +- content(必填):string —— 提示文案(纯文本) +- placement:'top' | 'bottom' —— 气泡方位;缺省 top(触发器上方) +- delay:number —— 出场延迟毫秒;缺省 150,传 0 立即显示 +- trigger(必填):HTMLElement —— 第二个参数:被包裹的触发器元素(按钮 / 输入框等任意 DOM) + +示例: + +``` +tooltip({ content: '保存后立即生效' }, button({ label: '保存', onClick: save })) +``` + +手把手: + +1. 先创建触发器元素,如 const btn = button({ label: '保存' }) +2. 用 tooltip(props, trigger) 包一层:返回带气泡的包裹元素,原触发器仍是独立节点 +3. 鼠标移入或键盘聚焦约 150ms 后出场,移出 / 失焦立即收起;按 Esc 可立刻关闭 +4. 气泡默认在上方,空间不足或需要避让时传 placement: 'bottom' +5. 气泡 pointer-events: none 不抢指针;判读依赖 aria-describedby + role='tooltip',读屏可读 +6. 只做展示:不要在气泡里放可点击元素,需要交互请用 modal 或自绘弹层 + +现场演示:apps/docs/demo.html#sec-tooltip + ### spinner — 加载指示器 Spinner 参数: @@ -418,6 +444,7 @@ API 速览: - card(props, ...children):卡片容器 - badge(props):徽标,variant = default | success | warning | danger - alert(props):提示条,variant = info | success | warning | danger +- tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起 - spinner(props):加载指示器,size 控制直径 - progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色 - tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签 diff --git a/llms.txt b/llms.txt index 4024713..0bc9adf 100644 --- a/llms.txt +++ b/llms.txt @@ -45,7 +45,7 @@ ## @ui-arch/ui (v0.1.0) - 类型: skin-dom · 目录: packages/skin/ui -- 描述: DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。 +- 描述: DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / tooltip / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。 - API: - button(props):按钮,variant = primary | ghost | danger - textField(props):文本输入,value 信号双向绑定 @@ -57,6 +57,7 @@ - card(props, ...children):卡片容器 - badge(props):徽标,variant = default | success | warning | danger - alert(props):提示条,variant = info | success | warning | danger + - tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起 - spinner(props):加载指示器,size 控制直径 - progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色 - tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签 diff --git a/packages/skin/ui/src/index.ts b/packages/skin/ui/src/index.ts index ab840ac..3a30be4 100644 --- a/packages/skin/ui/src/index.ts +++ b/packages/skin/ui/src/index.ts @@ -9,6 +9,7 @@ export { radioGroup } from './radioGroup.js'; export { card } from './card.js'; export { badge } from './badge.js'; export { alert } from './alert.js'; +export { tooltip } from './tooltip.js'; export { spinner } from './spinner.js'; export { progress } from './progress.js'; export { tabs } from './tabs.js'; diff --git a/packages/skin/ui/src/tooltip.ts b/packages/skin/ui/src/tooltip.ts new file mode 100644 index 0000000..f85cc92 --- /dev/null +++ b/packages/skin/ui/src/tooltip.ts @@ -0,0 +1,52 @@ +import { h, signal } from '@ui-arch/frame'; +import type { TooltipProps } from './types.js'; + +let seq = 0; // 全局自增序号:保证每个气泡 id 唯一,供 aria-describedby 关联 + +/*** 悬浮提示:包裹触发器,hover / focus 延迟出场,移出 / 失焦 / Esc 收起,纯展示不拦截指针 ***/ +export function tooltip(props: TooltipProps, trigger: HTMLElement): HTMLElement { + // —— 状态集中声明 —— + const open = signal(false); // 气泡显隐 + const id = `ua-tip-${++seq}`; // 气泡唯一 id + const delay = props.delay ?? 150; // 出场延迟毫秒;<=0 视为立即显示 + let timer: number | null = null; // 出场延迟计时器句柄 + + const show = () => { + if (timer != null) window.clearTimeout(timer); // 重复进入先清旧计时 + if (delay <= 0) return open(true); + timer = window.setTimeout(() => { + timer = null; + open(true); + }, delay); + }; + const hide = () => { + if (timer != null) { // 还没出场就离开:直接取消计时,避免闪一下 + window.clearTimeout(timer); + timer = null; + } + open(false); + }; + + // —— 触发器与气泡 —— + trigger.setAttribute('aria-describedby', id); // 无障碍:读屏把提示文案关联到触发器 + const bubble = h( + 'span', + { + id, + class: () => `ua-tip ua-tip-${props.placement ?? 'top'}${open() ? ' ua-open' : ''}`, + role: 'tooltip', + 'aria-hidden': () => String(!open()), + }, + props.content, + ); + const root = h('span', { class: 'ua-tip-wrap' }, trigger, bubble); + + root.addEventListener('pointerenter', show); // 鼠标进入 + root.addEventListener('pointerleave', hide); // 鼠标离开 + root.addEventListener('focusin', show); // 键盘聚焦(focusin 会冒泡) + root.addEventListener('focusout', hide); // 失焦 + root.addEventListener('keydown', (e: KeyboardEvent) => { + if (e.key === 'Escape') hide(); // Esc 立即收起,不必等延迟 + }); + return root; +} diff --git a/packages/skin/ui/src/types.ts b/packages/skin/ui/src/types.ts index bcd0dd8..a16174c 100644 --- a/packages/skin/ui/src/types.ts +++ b/packages/skin/ui/src/types.ts @@ -1,6 +1,13 @@ import type { ColumnDef, RowKey } from '@ui-arch/table-core'; import type { Signal } from '@ui-arch/frame'; +/*** 悬浮提示入参 ***/ +export interface TooltipProps { + content: string; // 提示文案(纯文本) + placement?: 'top' | 'bottom'; // 气泡方位;缺省 top(触发器上方) + delay?: number; // 出场延迟毫秒;缺省 150,传 0 立即显示 +} + /*** 按钮入参 ***/ export interface ButtonProps { label: string; // 按钮文案 diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index 857b38d..99f160a 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -1,7 +1,7 @@ { "name": "@ui-arch/ui", "type": "skin-dom", - "description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。", + "description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / tooltip / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。", "tags": [ "components", "dom", @@ -23,6 +23,7 @@ "card(props, ...children):卡片容器", "badge(props):徽标,variant = default | success | warning | danger", "alert(props):提示条,variant = info | success | warning | danger", + "tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起", "spinner(props):加载指示器,size 控制直径", "progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色", "tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签", @@ -43,6 +44,7 @@ "CardProps", "BadgeProps", "AlertProps", + "TooltipProps", "SpinnerProps", "ProgressProps", "TabsProps", @@ -61,7 +63,7 @@ "语义色 variant 四档:default|info / success / warning / danger,一律来自令牌,禁止硬编码颜色" ], "docs": { - "intro": "16 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。", + "intro": "17 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。", "steps": [ "安装依赖:pnpm add @ui-arch/ui @ui-arch/frame(workspace 内自动链接)", "引入样式:在应用入口 import '@ui-arch/ui/ui.css',暗色主题在根元素设 data-theme='dark'", @@ -356,6 +358,44 @@ "传入 message 即可,入场自带下滑动画" ] }, + { + "id": "tooltip", + "title": "悬浮提示 Tooltip", + "demo": "sec-tooltip", + "props": [ + { + "n": "content", + "t": "string", + "r": 1, + "d": "提示文案(纯文本)" + }, + { + "n": "placement", + "t": "'top' | 'bottom'", + "d": "气泡方位;缺省 top(触发器上方)" + }, + { + "n": "delay", + "t": "number", + "d": "出场延迟毫秒;缺省 150,传 0 立即显示" + }, + { + "n": "trigger", + "t": "HTMLElement", + "r": 1, + "d": "第二个参数:被包裹的触发器元素(按钮 / 输入框等任意 DOM)" + } + ], + "example": "tooltip({ content: '保存后立即生效' }, button({ label: '保存', onClick: save }))", + "steps": [ + "先创建触发器元素,如 const btn = button({ label: '保存' })", + "用 tooltip(props, trigger) 包一层:返回带气泡的包裹元素,原触发器仍是独立节点", + "鼠标移入或键盘聚焦约 150ms 后出场,移出 / 失焦立即收起;按 Esc 可立刻关闭", + "气泡默认在上方,空间不足或需要避让时传 placement: 'bottom'", + "气泡 pointer-events: none 不抢指针;判读依赖 aria-describedby + role='tooltip',读屏可读", + "只做展示:不要在气泡里放可点击元素,需要交互请用 modal 或自绘弹层" + ] + }, { "id": "spinner", "title": "加载指示器 Spinner", diff --git a/packages/skin/ui/ui.css b/packages/skin/ui/ui.css index e92ed2c..eebc5a1 100644 --- a/packages/skin/ui/ui.css +++ b/packages/skin/ui/ui.css @@ -613,6 +613,39 @@ box-shadow: 0 0 0 3px color-mix(in srgb, var(--ua-color-accent) 18%, transparent); } +/* —— 悬浮提示 —— */ +.ua-tip-wrap { + position: relative; + display: inline-flex; +} +.ua-tip { + position: absolute; + left: 50%; + z-index: 30; + max-width: 220px; + padding: var(--ua-space-1) var(--ua-space-2); + border-radius: var(--ua-radius-sm); + background: var(--ua-color-text); + color: var(--ua-color-bg); + font-size: var(--ua-font-size-sm); + line-height: 1.5; + pointer-events: none; + opacity: 0; + transition: opacity 0.16s ease-out, transform 0.16s ease-out; +} +.ua-tip-top { + bottom: calc(100% + 6px); + transform: translateX(-50%) translateY(3px); +} +.ua-tip-bottom { + top: calc(100% + 6px); + transform: translateX(-50%) translateY(-3px); +} +.ua-tip.ua-open { + opacity: 1; + transform: translateX(-50%) translateY(0); +} + /* —— 无障碍:用户偏好减少动效时关闭全部动画 —— */ @media (prefers-reduced-motion: reduce) { .ua-btn, @@ -630,6 +663,7 @@ .ua-progress-fill, .ua-progress-fill::after, .ua-alert, + .ua-tip, .ua-form-error, .ua-modal, .ua-modal-overlay {