关于 wix-cli-site-component
面向 Wix CLI 的技能,用于构建可在 Wix Editor 中自定义的 React 网站组件。它指导编写组件清单、React 实现、CSS、TypeScript 类型及必需的扩展注册。
主要功能
- 01编辑器组件清单设计
- 02带类型的 React 组件模式
- 03响应式 CSS 与 CSS 变量
- 04可配置内容与样式
- 05元素级编辑器配置
- 06必需的扩展注册
适用场景
- 01构建可自定义的个人资料卡
- 02创建内容可配置的主视觉区
- 03制作可编辑的功能列表
- 04为组件元素定义编辑器控件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wix/ skills --skill wix-cli-site-component安装后在 Claude Code 中输入/wix-cli-site-component确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/CSS_GUIDELINES.mdDESIGN_SYSTEM.mdEXAMPLE.mdMANIFEST_ADVANCED.mdMANIFEST_GUIDELINES.mdREACT_PATTERNS.mdTYPESCRIPT_QUALITY.md详细介绍
Wix 网站组件构建器
为 Wix CLI 应用创建生产级 React 网站组件及编辑器清单。网站组件是与 Wix Editor 集成的 React 组件,允许网站所有者通过可视化界面自定义内容、样式和行为。
先决条件: 编写任何文件前,先将 @wix/editor-react-types 安装为开发依赖。
架构
网站组件由 四个必需文件 组成:
1. 组件清单(manifest.json)
定义 React 组件与 Wix 生态系统之间的契约:
- editorElement:根元素配置(选择器、显示名称、原型、布局)
- cssProperties:用于样式自定义的 CSS API
- data:用于内容配置的数据 API
- elements:用于精细编辑的嵌套元素定义
- behaviors:编辑器交互行为
2. React 组件(component.tsx)
可用于生产环境的 React 函数组件:
- 实现与清单数据结构匹配的 props 接口
- 将 className 和 id 应用到根元素
- 通过
wix.elementsRemovalState处理元素移除状态 - 对嵌套元素使用子组件模式
- 包含正确的 TypeScript 类型和错误处理
3. CSS 样式(style.css)
采用现代 CSS 并支持响应式设计:
- 选择器与清单及 React classNames 保持同步
- 使用 CSS 变量实现动态样式
- 无需媒体查询即可实现响应式设计(flexbox、grid、clamp)
- 为编辑器元素启用指针事件
- 静态值不使用内联样式
- 每个选择器只出现一次,所有元素均设置
box-sizing: border-box - 不使用
transition: all,不使用媒体查询(prefers-reduced-motion除外) - 根元素显示方式:声明
--display: [value]CSS 变量,然后在根元素上使用display: var(--display)
4. TypeScript 类型(types.ts)
严格的类型定义:
- 导入类型:
import type { Wix, Link, Image, Text, NumberType, BooleanValue, WebUrl, Direction } from '@wix/editor-react-types'— 不要在本地定义这些类型(已在先决条件中安装) - 例外:
RichText— 在本地定义为type RichText = string(@wix/editor-react-types中的版本是{ text, html, linkList },而非纯字符串) - 为所有组件定义 props 接口
- 元素 props 结构使用可选链
组件清单结构
在实现网站组件前,必须阅读 MANIFEST_GUIDELINES.md。 其中包含完整的清单结构、所有数据类型、元素配置和必需模式。
清单使用以下关键部分定义编辑器契约:
installation(初始放置)
{
"installation": {
"staticContainer": "HOMEPAGE",
"initialSize": {
"width": { "sizingType": "pixels", "pixels": 400 },
"height": { "sizingType": "pixels", "pixels": 300 }
}
}
}
- staticContainer:使用
"HOMEPAGE",以便在 Harmony 编辑器中自动安装 - initialSize:使用
sizingType选项定义初始尺寸:"content"- 根据内容自动调整尺寸"stretched"- 填满可用空间"pixels"- 固定像素尺寸(需要pixels属性)
editorElement(根配置)
{
"selector": ".component-name",
"displayName": "Component Name",
"archetype": "Container",
"layout": {
"resizeDirection": "horizontalAndVertical",
"contentResizeDirection": "horizontal"
},
"cssProperties": {
"backgroundColor": {
"displayName": "Background Color",
"defaultValue": "#ffffff"
}
},
"data": {
"columns": {
"dataType": "number",
"displayName": "Number of Columns",
"number": { "minimum": 1, "maximum": 4 }
}
},
"elements": {
"title": {
"elementType": "inlineElement",
"inlineElement": {
"selector": ".component-name__title",
"displayName": "Title",
"data": {
"titleText": {
"dataType": "text",
"displayName": "Title Text"
}
},
"behaviors": {
"selectable": true,
"removable": true
}
}
}
}
}
数据类型参考
所有运行时类型均来自 @wix/editor-react-types。
Manifest dataType | TypeScript 类型 | 用途 |
|---|---|---|
text | Text | 名称、标题、描述 |
textEnum | TextEnum | 预定义选项 |
number | NumberType | 数量、尺寸 |
booleanValue | BooleanValue | 开关、标志 |
a11y | A11y | 无障碍属性 |
link | Link | 导航链接 |
image | Image | 图片 |
video | Video | 媒体内容 |
audio | Audio | 音频内容 |
vectorArt | VectorArt | 图标、图形 |
localDate | LocalDate (string, YYYY-MM-DD) | 日期值 |
localTime | LocalTime (string, hh:mm[:ss][.sss]) | 时间值 |
localDateTime | LocalDateTime (string, YYYY-MM-DDThh:mm[:ss][.sss]) | 日期 + 时间值 |
webUrl | WebUrl (string) | 外部 URL |
richText | RichText (define locally as string) | 格式化内容 |
arrayItems | ArrayItems | 集合、列表 |
direction | Direction | HTML dir 属性 |
menuItems | MenuItems | 导航菜单 |
CSS 属性参考
用于样式自定义的常见 CSS 属性:
- 布局:
display、gap、padding、margin、width、height - 排版:
font、fontSize、fontWeight、textAlign、color - 背景:
backgroundColor、backgroundImage - 边框:
border、borderRadius、boxShadow - 定位:
alignItems、justifyContent、flexDirection
**完整 CSS 属性参考:**所有 CSS 属性、变量模式和样式最佳实践,请参阅 CSS_GUIDELINES.md。
React 组件模式
**对于使用钩子、效果或回调的组件:**请参阅 REACT_PATTERNS.md;当组件使用 useEffect、useCallback、复杂状态或异步操作时,请阅读此文档。文档包含钩子、数组、引用和 SSR 安全数据获取的完整模式。
Props 结构
import type { Wix, Link, Image } from '@wix/editor-react-types'; // also: Text, NumberType, BooleanValue, WebUrl, Direction
interface ComponentProps {
// Standard props (always present)
className: string;
id: string;
wix?: Wix;
// Component-level data (from editorElement.data)
columns?: number;
layout?: string;
// Element props (from elements definitions)
elementProps?: {
title?: {
titleText?: string;
wix?: Wix;
};
button?: {
buttonText?: string;
buttonLink?: Link;
wix?: Wix;
};
};
}
子组件模式
将每个不同的 UI 元素提取为一个具名子组件。每个子组件都接收一个与 manifest 选择器匹配的 className 属性,以及自身的数据属性:
const Title: FC<{ titleText?: string; className: string }> = ({
titleText = "Default Title", className
}) => <h2 className={className}>{titleText}</h2>;
const MyComponent: FC<MyComponentProps> = ({ className, id, elementProps, wix }) => {
const removalState = wix?.elementsRemovalState || {};
return (
<div className={`my-component ${className}`} id={id}>
{!removalState['title'] && <Title className="my-component__title" {...elementProps?.title} />}
</div>
);
};
有关完整的子组件架构、数组处理和 TypeScript 模式,请参阅 REACT_PATTERNS.md。
条件渲染
根据 wix.elementsRemovalState 条件渲染所有元素:{!removalState['elementKey'] && <Element />},其中 removalState = wix?.elementsRemovalState || {}。
CSS 指南
响应式设计策略
组件位于用户可调整大小(300-1200px)的容器中,且视口大小各不相同:
- 根元素:
width: 100%; height: 100% - 布局结构:使用 CSS Grid 和 Flexbox 实现流式响应布局
- 排版:使用
clamp()实现流式缩放 - 间距:使用固定间距或变化范围较小的 clamp 间距(≤50%)
动态样式的 CSS 变量
.component {
--display: block;
--background-color: #ffffff;
--text-color: #333333;
display: var(--display);
background-color: var(--background-color);
color: var(--text-color);
pointer-events: auto;
}
选择器同步
**重要:**CSS 选择器必须与 manifest 选择器和 React classNames 完全匹配:
- React:
className="profile-card__name" - CSS:
.profile-card__name { ... } - Manifest:
"selector": ".profile-card__name"
设计指南
**完整参考:**有关视觉设计原则、创意指南和美学最佳实践,请参阅 DESIGN_SYSTEM.md。
通过间距传达信息
| 关系 | 数值 | 用途 |
|---|---|---|
| 紧密(图标 + 标签) | 0.25-0.5rem (4-8px) | 将相关项目聚合在一起 |
| 同一类别 | 1-1.5rem (16-24px) | 卡片分区、表单字段 |
| 不同分区 | 2-3rem (32-48px) | 主要内容块 |
| 强调/戏剧效果 | 4rem+ (64px+) | 主视觉内容、营造奢华感 |
视觉一致性
- 圆角半径:所有相似元素使用相同的圆角半径(0-4px 为锐利,6-12px 为圆润)
- 阴影级别:最多 3 个级别(静止、悬停、浮起)
- 元素高度:相似元素使用一致的高度
- 配色策略:有目的地使用完整调色板来呈现层级和区域
创意探索
突破显而易见的方案:
- 卡片:非对称网格、重叠元素、粗重的强调边框
- 列表:交替样式、聚焦图案、色彩节奏
- 交互元素:分体式按钮、彩色图标圆圈、平滑过渡
- 内容层级:用于统计数据的大号数字、引言式醒目提示、留白分隔线
组件元素指南
一个元素 = 一个清单条目
每个独立的视觉部分都需要单独的清单元素:
- ✅ 3 个按钮 → 3 个独立元素
- ✅ 图片 + 文本 → 2 个独立元素
- ❌ 将多个项目合并为一个元素
数据作用域规则
editorElement.data - 仅用于整个组件的配置:
- ✅ 布局枚举值、数字(列数:3,速度:500)
- ❌ 文本、链接、图片(应归属于元素)
- ❌ 显示/隐藏布尔值(改用 removable: true)
elements[key].data - 此特定元素的内容:
- ✅ 元素专属内容(标题文本、按钮链接、图片)
资源要求
组件需要默认图片时,请使用此格式:
// Import in component
import { heroImage } from './assets/defaultImages';
// Usage
<img src={heroImage} alt="Hero" />
资源规范格式:
<imageUrlName>
{ "description": "Modern cityscape at sunset", "width": 1920, "height": 1088 }
</imageUrlName>
规则:
- 从
'./assets/defaultImages'作为命名导出导入 - 宽度/高度:必须是 64 的倍数,范围为 128-2048px
- 绝不使用外部 URL
输出结构
src/extensions/site/components/
└── {component-name}/
├── manifest.json # Component manifest
├── component.tsx # React component
├── style.css # CSS styles
├── types.ts # TypeScript types
└── assets/ # Optional assets
└── defaultImages.ts
示例
完整可运行示例: 请参阅 EXAMPLE.md,其中包含带嵌套元素的个人资料卡、所有数据类型,以及三种组件类型(叶子、容器、根组件)。构建复杂的多元素组件时、需要确认所有模式是否正确时,或需要交叉参考时,请阅读此文档。对于包含 ≤5 个元素的组件,本文档中记录的模式已足够,无需阅读 EXAMPLE.md。
个人资料卡组件
请求:“创建一张团队成员个人资料卡,包含照片、姓名、工作经验和联系按钮”
输出:
- 清单包含 8 个元素,采用 2 层嵌套(照片区域、信息区域)
- React 组件包含叶子、容器和根子组件
- CSS 包含响应式布局和悬停效果
- 为所有属性和数据结构定义 TypeScript 类型
主视觉区域组件
请求:“构建一个主视觉区域,包含背景图片、标题、副标题和 CTA 按钮”
输出:
- 清单包含背景图片 CSS 属性和 3 个文本元素
- React 组件采用叠加式设计和排版层级
- CSS 包含响应式文本缩放和醒目的间距
- 默认主视觉图片的资源规范
功能列表组件
请求:“创建一个功能组件,支持配置项目数量”
输出:
- 清单使用 arrayItems 数据类型来存放功能集合
- React 组件遍历功能数组,并进行安全检查
- CSS 使用可根据项目数量调整的灵活网格布局
- 为功能图标、标题和描述提供子组件
扩展注册
扩展注册为强制要求,且必须完成两个步骤。
步骤 1:创建组件专属扩展文件
每个站点组件都需要在其文件夹中包含一个 extensions.ts 文件:
import { extensions } from "@wix/astro/builders";
import manifest from "./manifest.json";
export const sitecomponentMyComponent = extensions.siteComponent({
...manifest,
id: "{{GENERATE_UUID}}",
description: "My Component",
type: "<CODE_IDENTIFIER>.MyComponent",
resources: {
client: {
component: "./extensions/site/components/my-component/component.tsx",
componentUrl: "./extensions/site/components/my-component/component.tsx",
},
},
});
重要:类型命名约定
type 字段采用 {CODE_IDENTIFIER}.{PascalCaseFolderName} 格式:
- 文件夹
my-component→type: "<CODE_IDENTIFIER>.MyComponent" - 文件夹
profile-card→type: "<CODE_IDENTIFIER>.ProfileCard" - 文件夹
hero-section→type: "<CODE_IDENTIFIER>.HeroSection"
文件夹名称会转换为 PascalCase(移除连字符,并将每个单词的首字母大写)。
CODE_IDENTIFIER 要求: Code Identifier 是必填值,不能猜测。每个 Wix 应用都会自动获得一个。
如果提示词中提供了 Code Identifier:
- 将其用作类型前缀:
<actual-code-identifier>.ComponentName
如果提示词中未提供 Code Identifier:
- 在
type字段中使用占位符<CODE_IDENTIFIER>:<CODE_IDENTIFIER>.ComponentName - 在“手动操作事项”中添加:“将
<CODE_IDENTIFIER>替换为 Wix Dev Center 中的实际 Code Identifier”
重要:UUID 生成
id 必须是唯一且固定的 UUID v4 字符串。为每个扩展生成一个新的 UUID——不要使用 randomUUID(),也不要复制示例中的 UUID。
步骤 2:在主扩展文件中注册
**重要:**创建组件专属扩展文件后,必须阅读 wix-cli-extension-registration,并按照“应用注册”部分的说明更新 src/extensions.ts。
如果未完成步骤 2,该站点组件将无法在 Wix Editor 中使用。
代码质量要求
**完整参考:**严格的 TypeScript 配置和代码质量标准请参阅 TYPESCRIPT_QUALITY.md。
TypeScript 标准
- 使用严格的 TypeScript,不得使用
any类型 - 所有数据属性都必须是可选的(使用
?) - 所有函数都必须显式声明返回类型
- 使用可选链正确处理 null/undefined
- 不得使用
@ts-ignore或@ts-expect-error注释
React 最佳实践
- 兼容 React 16——不得使用 React 18+ 特性(
useId、useDeferredValue、useTransition等) - 使用带 hooks 的函数组件
- 为 useEffect 设置正确的依赖数组
- 组件必须响应属性变化
- 代码必须兼容 SSR(模块作用域中不得使用浏览器 API)
ESLint 合规要求
- 不得有未使用的变量/参数/导入项(
@typescript-eslint/no-unused-vars) - 不得使用外部图片:
img的src不得为https://...(允许本地导入、wixstatic.com、变量) - 兼容 SSR:模块作用域/构造函数中不得使用
window/document;在useEffect/处理函数中使用浏览器 API 时必须添加保护 - 不得使用
dangerouslySetInnerHTML或内联<style>标签——动态值应使用 CSS 变量或内联style属性 - 不得使用
window.fetch(no-restricted-properties) - Hooks 的
exhaustive-deps:在useEffect/useCallback中使用的组件作用域内所有值都必须列入依赖数组 - 使用
const/let(不得使用var),不得使用未知的 JSX 属性
常见错误
| 错误 | 失败原因 | 修复方法 |
|---|---|---|
| CSS 选择器与清单不匹配 | 编辑器无法将样式应用到该元素 | 确保清单中的 selector、React className 和 CSS 选择器完全一致 |
将内容文本放在 editorElement.data 中 | 内容应属于特定元素,而非根元素 | 将文本/图像/链接数据移到 elements[key].data 中 |
直接在根元素上使用 display: flex | 会破坏编辑器覆盖机制 | 使用 --display: flex CSS 变量,然后设置 display: var(--display) |
元素缺少 removable: true | 网站所有者无法隐藏该元素 | 为所有元素添加 behaviors: { selectable: true, removable: true } |
arrayItems 没有 data/dataItem/dynamicItems | 部署验证失败 | arrayItems 对象必须包含以下之一:data、dataItem 或 dynamicItems |
在模块作用域使用 window/document | 构建期间 SSR 会失败 | 在 useEffect 或事件处理程序中保护浏览器 API 调用 |
从 @wix/design-system 导入 | 网站组件无法使用 | 仅使用纯 HTML/CSS 或自定义组件 |
import { FC } from 'react' | Astro tsconfig 中的 verbatimModuleSyntax 要求仅导入类型 | 使用 import { type FC } 或从 React 导入 import type { FC } |
硬性约束
- 不要虚构或假定新的类型、模块、函数、属性、事件或导入
- 仅使用提供的参考资料中明确列出的实体,或本项目已使用的标准库
- 不要添加依赖;不要使用
@wix/design-system或@wix/wix-ui-icons-common - 所有面向用户的内容都必须来自属性(不得硬编码文本)
- 链接/媒体只能来自清单,绝不能硬编码 URL
- 绝不要在任何代码中使用模拟内容、占位符或 TODO
- 始终实现完整且可用于生产环境的功能
参考文档
| 文件 | 阅读时机 |
|---|---|
| MANIFEST_GUIDELINES.md | 始终阅读——清单结构、元素规则、CSS 属性、同步 |
| MANIFEST_ADVANCED.md | 使用 arrayItems、链接约束、richText 功能或非默认安装尺寸时 |
| REACT_PATTERNS.md | 使用钩子(useEffect、useCallback)、复杂状态或数组时 |
| EXAMPLE.md | 构建复杂(5 个以上元素)组件时,或用于核对所有模式 |
| CSS_GUIDELINES.md | 需要高级 CSS 模式或动画时 |
| DESIGN_SYSTEM.md | 构建视觉丰富或具有品牌特色的组件时 |
| TYPESCRIPT_QUALITY.md | 需要严格的 TypeScript 配置和属性接口模式时 |