mcpField
U
ui-translation

ui-translation

github.com/iress设计与 UI159 次安装1 天前更新
代码仓库

关于 ui-translation

将自然语言 UI 描述转为使用 Iress Design System 组件和 tokens 的实现方案。该 Skill 强调查阅组件文档、构建响应式布局,并遵循一致的样式与无障碍实践。

主要功能

  1. 01将 UI 描述映射到 IDS 组件
  2. 02查阅文档核实组件能力
  3. 03构建响应式布局
  4. 04使用 IDS 样式属性与 tokens
  5. 05检查导入和实现模式
  6. 06遵循表单与无障碍指引

适用场景

  1. 01实现描述中的表单或登录页
  2. 02构建响应式仪表盘和导航
  3. 03将设置页转换为 IDS 组件
  4. 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)组件实现。

翻译工作流

  1. 识别 UI 元素 — 将描述拆分为组件:操作(按钮)、输入(字段)、布局(堆叠、网格)、内容(文本、卡片)、覆盖层(模态框、滑出面板)、导航
  2. 映射到 IDS 组件 — 使用组件映射为每个元素找到合适的 IDS 组件
  3. 验证组件功能 — 推荐组件前,先阅读其 .ai/components/<name>.md 文档(位于 node_modules/@iress-oss/ids-components/.ai/components/),确认其支持所需功能(异步、筛选、验证等)
  4. 应用布局 — 仅在需要时,使用 IressStack(垂直)、IressInline(水平)或 IressRow/IressCol(网格)包裹元素。添加包装组件前,检查父组件是否已提供布局(例如卡片页脚、模态框操作区、按钮组)。切勿用布局组件包裹单个子元素。网格始终使用 span={{ xs: 12, md: ... }} 实现响应式布局
  5. 添加响应式行为 — 即使描述中只提到桌面端,也要在移动端堆叠列,并将次要内容移至 IressSlideout 或可折叠分区
  6. 应用样式 — 使用样式属性设置间距、颜色和排版。间距令牌必须包含类别前缀:gap="spacing.4"、p="spacing.6"。别名令牌("xs"、"sm"、"md"、"lg"、"xl")也有效。切勿使用 gap="4" 这样的纯数字
  7. 验证输出 — 检查所有导入均可解析,不要在存在 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 描述时,都应遵循以下原则:

  1. 识别主要任务 — 用户想要完成什么?移动端布局应聚焦于此任务,并将其他内容置于次要入口
  2. 堆叠多列布局 — 并排的列在移动端应堆叠为全宽(span={{ xs: 12, md: ... }})
  3. 重新安置次要内容 — 在移动端,将补充 UI(筛选器、侧边栏、元数据面板、次要操作)移入 IressSlideout、IressModal 或可折叠分区
  4. 简化密集布局 — 对于包含许多列的表格或多面板仪表板,使用 hideBelow 隐藏非必要列、折叠分区,或使用 useBreakpoint 切换为卡片布局
  5. 保留所有功能 — 切勿在移动端移除功能。使用 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>
  );
}

最佳实践

  1. 尽量减少组件嵌套 — 使用尽可能少的组件来实现布局。每个包装组件都应有其存在的理由。添加 IressInline 或 IressStack 之前,请先确认父组件是否已处理布局(例如,IressCard 提供 heading 和 footer 属性;IressModal 提供 actions;IressButtonGroup 可处理按钮的水平布局)。请参阅下文“常见错误”中的“不必要的布局包装器”部分。
  2. 始终使用 IressProvider 包装 — 应在应用根节点使用,以提供字体和 CSS 变量。IressProvider 已包含 IressModalProvider、IressSlideoutProvider、IressToasterProvider、IressPopoverProvider 和 IressIconProvider——请勿单独添加这些 Provider。如果使用 IressShadow,则无需添加其他 Provider,因为它内部已包含 IressProvider。
  3. 所有表单输入均使用 IressField — 提供一致的标签、提示和验证显示。
  4. 仅在需要时使用 IressStack/IressInline — 优先使用它们,而非自定义 CSS flex/grid;但如果父组件已提供间距或布局,则不要添加。
  5. 使用正确的间距 token 格式 — 始终添加 token 类别前缀:gap="spacing.4"、p="spacing.6"。别名 token("xs"、"sm"、"md"、"lg"、"xl")也有效。切勿使用 gap="4" 这样的裸数字。
  6. 使用语义化按钮模式 — 每个区块使用一个 primary,大多数操作使用 secondary。
  7. 始终包含标签 — 所有表单输入都需要通过 IressField 提供无障碍标签。
  8. 使用状态反馈 — 行内消息使用 IressAlert,确认对话框使用 IressModal status="danger",按钮则通过 status 属性显示危险/成功状态。
  9. 优先使用 IDS 组件 — 使用 IressText 而非原生 <p>,使用 IressButton 而非 <button>。
  10. 在 IressText 中使用原生元素没有问题 — 渲染 CMS 内容、markdown 输出或其他非结构化数据源时,可以在 IressText 内嵌套原生 HTML 元素(例如 <p>、<strong>、<a>、<ul>)。这样既能让 IressText 提供一致的排版,也能灵活组织内部内容结构。
  11. 始终让网格布局适配响应式尺寸 — 使用 IressRow/IressCol 时,请使用响应式 span 值(例如 span={{ xs: 12, md: 6 }}),让列在移动设备上堆叠,而不是溢出。
  12. 查看组件文档 — 阅读具体组件的文档,了解详细属性和模式(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)。

评论

支持 Markdown