关于 ui-translation
将自然语言 UI 描述转为使用 Iress Design System 组件和 tokens 的实现方案。该 Skill 强调查阅组件文档、构建响应式布局,并遵循一致的样式与无障碍实践。
主要功能
- 01将 UI 描述映射到 IDS 组件
- 02查阅文档核实组件能力
- 03构建响应式布局
- 04使用 IDS 样式属性与 tokens
- 05检查导入和实现模式
- 06遵循表单与无障碍指引
适用场景
- 01实现描述中的表单或登录页
- 02构建响应式仪表盘和导航
- 03将设置页转换为 IDS 组件
- 04检查生成的 UI 是否存在常见问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ iress/ design-system --skill ui-translation安装后在 Claude Code 中输入/ui-translation确认已加载。
附带文件references/component-mapping.mdreferences/styling-props.md
详细介绍
技能:UI 翻译
用途
使用 @iress-oss/ids-components 和 @iress-oss/ids-tokens,将自然语言 UI 描述转换为 IDS(Iress Design System)组件实现。
翻译工作流
- 识别 UI 元素 — 将描述拆分为组件:操作(按钮)、输入(字段)、布局(堆叠、网格)、内容(文本、卡片)、覆盖层(模态框、滑出面板)、导航
- 映射到 IDS 组件 — 使用组件映射为每个元素找到合适的 IDS 组件
- 验证组件功能 — 推荐组件前,先阅读其
.ai/components/<name>.md文档(位于node_modules/@iress-oss/ids-components/.ai/components/),确认其支持所需功能(异步、筛选、验证等) - 应用布局 — 仅在需要时,使用
IressStack(垂直)、IressInline(水平)或IressRow/IressCol(网格)包裹元素。添加包装组件前,检查父组件是否已提供布局(例如卡片页脚、模态框操作区、按钮组)。切勿用布局组件包裹单个子元素。网格始终使用span={{ xs: 12, md: ... }}实现响应式布局 - 添加响应式行为 — 即使描述中只提到桌面端,也要在移动端堆叠列,并将次要内容移至
IressSlideout或可折叠分区 - 应用样式 — 使用样式属性设置间距、颜色和排版。间距令牌必须包含类别前缀:
gap="spacing.4"、p="spacing.6"。别名令牌("xs"、"sm"、"md"、"lg"、"xl")也有效。切勿使用gap="4"这样的纯数字 - 验证输出 — 检查所有导入均可解析,不要在存在 IDS 组件时使用原始 HTML,网格布局使用响应式
span值,并且不存在常见反模式(禁用按钮、slot 属性、冗余的 textStyle)
设置
重要: IDS v6 当前处于 beta 阶段。请使用
@beta标签安装:npm install @iress-oss/ids-components@beta # If using tokens directly: npm install @iress-oss/ids-tokens@beta
import '@iress-oss/ids-components/dist/style.css'; // Required — component styles
import '@iress-oss/ids-tokens/build/css-vars.css'; // Required if using tokens directly
import {
IressProvider,
IressButton,
IressInput,
IressField,
IressStack,
IressInline,
IressText,
IressCard,
// ... import what you need
} from '@iress-oss/ids-components';
// Wrap your app in IressProvider (handles fonts + CSS variables)
function App() {
return <IressProvider>{/* your UI */}</IressProvider>;
}
组件映射
需要为 UI 元素查找合适的 IDS 组件时,请阅读 references/component-mapping.md,其中包含完整的“描述 → IDS 组件”映射表(操作、表单输入、布局、内容、覆盖层、导航、表格)。
样式属性
需要应用间距、颜色、可见性或排版属性时,请阅读 references/styling-props.md,查看完整的 IressCSSProps 参考和可接受的值。
响应式布局
始终生成响应式输出。 即使 UI 描述中只提到桌面布局,每个翻译都应适配较小屏幕。IDS 使用包含 6 个断点(xs、sm、md、lg、xl、xxl)的 12 列网格。
响应式设计原则
翻译任何 UI 描述时,都应遵循以下原则:
- 识别主要任务 — 用户想要完成什么?移动端布局应聚焦于此任务,并将其他内容置于次要入口
- 堆叠多列布局 — 并排的列在移动端应堆叠为全宽(
span={{ xs: 12, md: ... }}) - 重新安置次要内容 — 在移动端,将补充 UI(筛选器、侧边栏、元数据面板、次要操作)移入
IressSlideout、IressModal或可折叠分区 - 简化密集布局 — 对于包含许多列的表格或多面板仪表板,使用
hideBelow隐藏非必要列、折叠分区,或使用useBreakpoint切换为卡片布局 - 保留所有功能 — 切勿在移动端移除功能。使用
IressSlideout、IressModal、可展开分区或IressTabSet,确保功能易于访问且不使视图杂乱
响应式属性
许多属性可接受单个值,或以断点为键的对象:
// Full-width on mobile, half on medium+
<IressCol span={{ xs: 12, md: 6 }} />
// Tighter gap on mobile, larger on desktop
<IressRow gutter={{ xs: 'sm', md: 'lg' }} />
支持响应式值的属性:span、offset、gap、gutter、rowGap、p、px、py、m、mx、my、width,以及所有方向的 margin/padding 属性。
响应式可见性
直接在任何组件上使用 hideFrom/hideBelow CSS 属性:
<IressButton hideBelow="md">Desktop action</IressButton>
<IressText hideFrom="lg">Mobile only text</IressText>
若要根据断点进行条件渲染(例如,渲染完全不同的组件),请使用 useBreakpoint hook:
import { useBreakpoint } from '@iress-oss/ids-components';
function Navigation() {
const { breakpoint } = useBreakpoint();
const isMobile = breakpoint === 'xs' || breakpoint === 'sm';
return isMobile ? <MobileNav /> : <DesktopNav />;
}
翻译示例
“一个包含电子邮件和密码字段以及提交按钮的登录表单”
import {
IressButton,
IressField,
IressInput,
IressStack,
} from '@iress-oss/ids-components';
function LoginForm() {
return (
<IressStack gap="md">
<IressField label="Email" htmlFor="email" required>
<IressInput id="email" type="email" placeholder="Enter your email" />
</IressField>
<IressField label="Password" htmlFor="password" required>
<IressInput
id="password"
type="password"
placeholder="Enter your password"
/>
</IressField>
<IressButton mode="primary" type="submit">
Log in
</IressButton>
</IressStack>
);
}
“一张包含标题、描述和两个操作按钮的卡片”
import { IressCard, IressButton, IressInline } from '@iress-oss/ids-components';
function ActionCard() {
return (
<IressCard
heading={<h3>Card Title</h3>}
footer={
<IressInline gap="sm">
<IressButton mode="primary">Confirm</IressButton>
<IressButton mode="secondary">Cancel</IressButton>
</IressInline>
}
>
This is the card description with supporting details.
</IressCard>
);
}
“一个包含切换开关、一些复选框和保存按钮的设置页面”
import {
IressStack,
IressToggle,
IressCheckboxGroup,
IressCheckbox,
IressButton,
IressText,
IressDivider,
IressField,
} from '@iress-oss/ids-components';
function SettingsPage() {
return (
<IressStack gap="lg">
<IressText element="h2">Settings</IressText>
<IressToggle>Enable notifications</IressToggle>
<IressDivider />
<IressField label="Notification types">
<IressCheckboxGroup name="notification-types">
<IressCheckbox value="email">Email</IressCheckbox>
<IressCheckbox value="sms">SMS</IressCheckbox>
<IressCheckbox value="push">Push</IressCheckbox>
</IressCheckboxGroup>
</IressField>
<IressDivider />
<IressButton mode="primary">Save settings</IressButton>
</IressStack>
);
}
“一个包含侧边栏和主内容区域的仪表板”
注意:尽管描述中没有提到移动设备,但侧边栏属于次要内容——在移动设备上,应将其移入滑出面板,让用户专注于主内容。
import { useState } from 'react';
import {
IressRow,
IressCol,
IressStack,
IressText,
IressCard,
IressButton,
IressSlideout,
useBreakpoint,
} from '@iress-oss/ids-components';
function Dashboard() {
const { breakpoint } = useBreakpoint();
const isMobile = breakpoint === 'xs' || breakpoint === 'sm';
const [navOpen, setNavOpen] = useState(false);
const nav = (
<IressCard heading={<h3>Navigation</h3>}>
Menu items here
</IressCard>
);
return isMobile ? (
<IressStack gap="md">
<IressButton
mode="secondary"
icon="menu"
onClick={() => setNavOpen(true)}
>
Menu
</IressButton>
<IressCard>
<IressText element="h2">Main Content</IressText>
</IressCard>
<IressSlideout
heading="Navigation"
show={navOpen}
onShowChange={setNavOpen}
>
{nav}
</IressSlideout>
</IressStack>
) : (
<IressRow gutter="lg">
<IressCol span={3}>{nav}</IressCol>
<IressCol span={9}>
<IressCard>
<IressText element="h2">Main Content</IressText>
</IressCard>
</IressCol>
</IressRow>
);
}
最佳实践
- 尽量减少组件嵌套 — 使用尽可能少的组件来实现布局。每个包装组件都应有其存在的理由。添加
IressInline或IressStack之前,请先确认父组件是否已处理布局(例如,IressCard提供heading和footer属性;IressModal提供actions;IressButtonGroup可处理按钮的水平布局)。请参阅下文“常见错误”中的“不必要的布局包装器”部分。 - 始终使用 IressProvider 包装 — 应在应用根节点使用,以提供字体和 CSS 变量。
IressProvider已包含IressModalProvider、IressSlideoutProvider、IressToasterProvider、IressPopoverProvider和IressIconProvider——请勿单独添加这些 Provider。如果使用IressShadow,则无需添加其他 Provider,因为它内部已包含IressProvider。 - 所有表单输入均使用 IressField — 提供一致的标签、提示和验证显示。
- 仅在需要时使用 IressStack/IressInline — 优先使用它们,而非自定义 CSS flex/grid;但如果父组件已提供间距或布局,则不要添加。
- 使用正确的间距 token 格式 — 始终添加 token 类别前缀:
gap="spacing.4"、p="spacing.6"。别名 token("xs"、"sm"、"md"、"lg"、"xl")也有效。切勿使用gap="4"这样的裸数字。 - 使用语义化按钮模式 — 每个区块使用一个
primary,大多数操作使用secondary。 - 始终包含标签 — 所有表单输入都需要通过
IressField提供无障碍标签。 - 使用状态反馈 — 行内消息使用
IressAlert,确认对话框使用IressModal status="danger",按钮则通过status属性显示危险/成功状态。 - 优先使用 IDS 组件 — 使用
IressText而非原生<p>,使用IressButton而非<button>。 - 在
IressText中使用原生元素没有问题 — 渲染 CMS 内容、markdown 输出或其他非结构化数据源时,可以在IressText内嵌套原生 HTML 元素(例如<p>、<strong>、<a>、<ul>)。这样既能让IressText提供一致的排版,也能灵活组织内部内容结构。 - 始终让网格布局适配响应式尺寸 — 使用
IressRow/IressCol时,请使用响应式span值(例如span={{ xs: 12, md: 6 }}),让列在移动设备上堆叠,而不是溢出。 - 查看组件文档 — 阅读具体组件的文档,了解详细属性和模式(
node_modules/@iress-oss/ids-components/.ai/components/)。
常见错误
不必要的布局包装器
最常见的错误是在没有实际作用时,用 IressInline 或 IressStack 包裹子元素。每个包装器都必须有用途——如果移除它后结果不变,就应该移除。
// ❌ Unnecessary nesting — IressStack wrapping a single child
<IressStack gap="md">
<IressInline gap="sm">
<IressButton mode="primary">Save</IressButton>
<IressButton mode="secondary">Cancel</IressButton>
</IressInline>
</IressStack>
// ✅ Single group of buttons only needs IressInline
<IressInline gap="sm">
<IressButton mode="primary">Save</IressButton>
<IressButton mode="secondary">Cancel</IressButton>
</IressInline>
// ❌ Wrapping content that's already a single block
<IressStack gap="md">
<IressText element="h2">Title</IressText>
</IressStack>
// ✅ No wrapper needed for a single element
<IressText element="h2">Title</IressText>
何时使用布局包装器:
IressStack——有 2 个或更多块级同级元素,且它们之间需要垂直间距时IressInline——有 2 个或更多元素需要并排放置时(例如卡片footer中的按钮、操作栏)
何时不应使用:
- 父组件已经负责处理布局(例如模态框的
actions属性、按钮组) - 只有一个子元素——用包装器包裹单个子元素没有任何作用
- 嵌套使用
IressInline(IressInline中再嵌套IressInline)或IressStack(IressStack中再嵌套IressStack),但间距或对齐方式没有变化——此时应改为扁平结构
其他常见反模式
如需查看常见反模式的完整列表(禁用按钮、多余的 textStyle、旧式插槽属性、原始 HTML、硬编码值),请阅读 node_modules/@iress-oss/ids-components/.ai/guides/foundations-common-mistakes.md 中的「常见错误」指南(需要安装 @iress-oss/ids-components)。