platform-widget-generate
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGenerating a Widget Bundle
生成Widget Bundle
Author a complete WidgetBundle: a UEM tree (), a JSON Schema describing the widget's input contract, and the that registers the bundle.
tile/widget.uiwidget-meta.xml编写完整的WidgetBundle:包含UEM树()、描述widget输入契约的JSON Schema,以及用于注册bundle的文件。
tile/widget.uiwidget-meta.xmlWhen to Use This Skill
何时使用此技能
Use when the user asks for a widget, mosaic, fragment, or card-style rich UI surface. Do not use this skill for custom-LWC renderers or for files inside a Custom Lightning Type bundle — those belong to .
renderer.jsonplatform-custom-lightning-type-generate当用户请求widget、mosaic、fragment或卡片式富UI界面时使用。请勿将此技能用于自定义LWC渲染器,或Custom Lightning Type bundle内的文件——这些场景应使用。
renderer.jsonplatform-custom-lightning-type-generateInputs
输入参数
- (required) —
widgetNameidentifier; becomes the directory name undercamelCase.uiWidgets/ - A shape — what data the widget renders. The widget cannot be generated without it. The shape arrives one of two ways, in priority order:
- —
lightningTypeSchemafor an existing Apex-backed Lightning Type. The FQN takes one of two forms: outer-class ({ path, apexClassFqn }) where the outer class is the payload, or inner-class (<namespace>__<ClassName>) where the named inner class is the payload. Passed in by the<namespace>__<ClassName>$<InnerClass>orchestrator. When present, derive perplatform-lightning-type-widget-coordinate.references/schema-from-lightning-type.md - Extracted from the user's prompt — when no is passed, infer the shape directly from what the user wrote: a pasted JSON payload, an enumerated field list ("id as string, total as number"), or descriptive prose. The output is the same ordered list of
lightningTypeSchemaeither way.{ name, type, required }
If neither source yields a shape, STOP and ask the user before proceeding.
- (必填)——驼峰式(
widgetName)标识符;将作为camelCase目录下的子目录名称。uiWidgets/ - 数据结构——widget要渲染的数据。没有数据结构则无法生成widget。数据结构通过以下两种方式提供,优先级如下:
- ——现有Apex-backed Lightning Type的
lightningTypeSchema。FQN有两种形式:外部类({ path, apexClassFqn },其中外部类为负载),或内部类(<namespace>__<ClassName>,其中指定的内部类为负载)。由<namespace>__<ClassName>$<InnerClass>编排器传入。若存在,请根据platform-lightning-type-widget-coordinate推导。references/schema-from-lightning-type.md - 从用户提示中提取——当未传入时,直接从用户的描述中推断数据结构:粘贴的JSON负载、枚举字段列表(如"id为字符串,total为数字")或描述性文本。无论哪种方式,输出均为有序的
lightningTypeSchema列表。{ name, type, required }
若两种来源均无法得到数据结构,请停止操作并询问用户。
Output
输出结果
Three files in :
<pkgDir>/uiWidgets/<widgetName>/| File | Content |
|---|---|
| Widget envelope — |
| JSON Schema — root has |
| |
See for the resolution procedure and the exact shape.
references/widget-bundle-layout.md<pkgDir><widgetName>.uiwidget-meta.xml在目录下生成三个文件:
<pkgDir>/uiWidgets/<widgetName>/| 文件 | 内容 |
|---|---|
| Widget信封—— |
| JSON Schema——根节点包含 |
| |
有关的解析流程以及的具体结构,请参阅。
<pkgDir><widgetName>.uiwidget-meta.xmlreferences/widget-bundle-layout.mdComposition
结构组成
A widget body is a UEM tree of blocks nested under . The root node is . Every node — root and non-root — has the same shape: no key; just , optional , optional , and optional . Block shape:
contentBody.widgetBodytile/widgettypedefinitionattributesmetachildrents
interface Block {
definition: string // {namespace}/{blockName} — root is "tile/widget"
attributes?: Record<string, any>
meta?: { // see references/widget-meta-directives.md
forEach?: string
forItem?: string
if?: string
}
children?: Block[]
}The first child of SHOULD be a single (or a single ). All widget content typically goes inside that first child for predictable vertical structure across surfaces.
tile/widget.childrentile/columntile/cardWidget主体是嵌套在下的UEM块树,根节点为。所有节点(根节点和非根节点)结构相同:无键;仅包含、可选的、可选的和可选的。块结构如下:
contentBody.widgetBodytile/widgettypedefinitionattributesmetachildrents
interface Block {
definition: string // {namespace}/{blockName} — 根节点为"tile/widget"
attributes?: Record<string, any>
meta?: { // 请参阅references/widget-meta-directives.md
forEach?: string
forItem?: string
if?: string
}
children?: Block[]
}tile/widget.childrentile/columntile/cardAvailable Metadata Actions
可用元数据操作
discoverUiComponents
discoverUiComponents
Purpose: Discover the palette of blocks available for composition.
Required parameters: , , . Optional: to filter by name/description.
actionName: "discoverUiComponents"metadataType: "FRAGMENT"parameters.pageType: "FRAGMENT"searchQueryReturns: list of .
{ definition, description, label, attributes? }用途: 发现可用于组合的块组件库。
必填参数: ,,。可选参数:,用于按名称/描述过滤。
actionName: "discoverUiComponents"metadataType: "FRAGMENT"parameters.pageType: "FRAGMENT"searchQuery返回值: 列表。
{ definition, description, label, attributes? }getUiComponentSchemas
getUiComponentSchemas
Purpose: Fetch JSON schemas (property types, required vs optional, validation) for selected blocks.
Required parameters: , , , . Optional: (default ).
actionName: "getUiComponentSchemas"metadataType: "FRAGMENT"parameters.pageType: "FRAGMENT"parameters.componentDefinitions: ["namespace/definition", ...]includeKnowledgetrueReturns: — success entries carry the JSON schema, failure entries carry an error message. Partial failures are supported.
componentSchemas[]Never passtotile/widget— it is a fixed wrapper, not a queryable component.getUiComponentSchemas
用途: 获取所选块的JSON Schema(属性类型、必填/可选、验证规则)。
必填参数: ,,,。可选参数:(默认值)。
actionName: "getUiComponentSchemas"metadataType: "FRAGMENT"parameters.pageType: "FRAGMENT"parameters.componentDefinitions: ["namespace/definition", ...]includeKnowledgetrue返回值: ——成功条目包含JSON Schema,失败条目包含错误信息。支持部分失败。
componentSchemas[]请勿将传入tile/widget——它是固定的包装器,并非可查询的组件。getUiComponentSchemas
Attribute Binding
属性绑定
- Bind a block property to runtime data with .
{!$attrs.<attrName>}MUST match a property name in<attrName>.schema.json - Inside a , reference the loop variable instead — e.g.
forEach. See"text": "{!$item.name}".references/widget-meta-directives.md
- 使用将块属性绑定到运行时数据。
{!$attrs.<attrName>}必须与<attrName>中的属性名称匹配。schema.json - 在循环内,请改用循环变量引用——例如
forEach。请参阅"text": "{!$item.name}"。references/widget-meta-directives.md
Layout Best Practices
布局最佳实践
These conventions cover widget structure — how blocks are grouped and stacked.
| Primitive | Purpose | When to use |
|---|---|---|
| Vertical stack of children | Root wrapper, and any group of blocks that should stack |
| Horizontal stack of children | Two or more blocks that belong on the same line |
| Visually-boxed group | A bounded section that should read as one unit |
| Whitespace between blocks | When extra space is needed between content groups |
- Sectioning: Separate major content groups with a fresh -bounded section. Do not nest cards inside cards.
tile/card - Nesting: Prefer flat layouts. Only nest a inside a
tile/column(or vice versa) when the visual orientation actually changes for that subgroup.tile/row - Authoritative palette: the table above lists typical layout primitives. Always confirm a block exists by inspecting output — do not assume a block name from this table without seeing it in the discovery response.
discoverUiComponents
这些约定涵盖widget的结构——块如何分组和堆叠。
| 基础组件 | 用途 | 使用场景 |
|---|---|---|
| 垂直堆叠子组件 | 根包装器,以及所有需要垂直堆叠的块组 |
| 水平堆叠子组件 | 两个或多个需要放在同一行的块 |
| 带视觉边框的组 | 需要作为一个整体呈现的有界区域 |
| 块之间的空白区域 | 内容组之间需要额外空间时 |
- 分区: 使用新的边界区域分隔主要内容组。请勿在卡片内嵌套卡片。
tile/card - 嵌套: 优先使用扁平化布局。仅当子组的视觉方向确实需要改变时,才在内嵌套
tile/row(反之亦然)。tile/column - 权威组件库: 上表列出了典型的布局基础组件。请始终通过查看的输出确认块是否存在——不要仅凭此表中的块名称假设其存在,必须在发现响应中看到该名称。
discoverUiComponents
Styling Best Practices
样式最佳实践
Widgets express intent, not pixels. Each surface provides a default look and feel; brand/theme overrides apply automatically.
- Style semantically. Use ,
variant, and other enum-typed attributes (size,primary,destructive,success). Do not pin literal colors or pixel values.warning - One primary action per visible group. At most one with
tile/button. Usevariant: primary,secondary, oroutlinefor additional actions.ghost - One per widget. Use
h1/h2for sub-section headings,h3for prose,bodyfor helper text.caption - Use semantic state variants on state-bearing blocks (,
tile/alert,tile/badge,tile/callout).tile/chip - Accept schema defaults for ,
gap,paddingunless there is a specific reason to override.size - Don't pin ,
width,heightunless a content constraint requires it. For long text, usemaxWidth.truncate: true - Use the Lucide icon set. Pass the Lucide name (,
"check"); other icon libraries are not supported."alert-circle"
Widget传递的是意图,而非像素细节。每个界面都提供默认的外观和风格;品牌/主题覆盖会自动应用。
- 语义化样式。 使用、
variant和其他枚举类型属性(如size、primary、destructive、success)。不要硬编码具体颜色或像素值。warning - 每个可见组最多一个主操作。 最多保留一个的
variant: primary。其他操作使用tile/button、secondary或outline变体。ghost - 每个widget最多一个标题。 子区域标题使用
h1/h2,正文使用h3,辅助文本使用body。caption - 在承载状态的块上使用语义化状态变体(如、
tile/alert、tile/badge、tile/callout)。tile/chip - 接受、
gap、padding的Schema默认值,除非有特定理由需要覆盖。size - 不要硬编码、
width、height,除非内容约束要求。对于长文本,请使用maxWidth。truncate: true - 使用Lucide图标集。 传入Lucide图标名称(如、
"check");不支持其他图标库。"alert-circle"
Workflow
工作流程
-
Resolve the widget spec — an ordered list of. Source depends on which input was provided (see Inputs):
{ name, type, required }- If was passed by the orchestrator → derive per
lightningTypeSchema.references/schema-from-lightning-type.md - Otherwise → infer the list directly from the user prompt (pasted JSON payload, enumerated field list, or descriptive prose).
- If
-
Discover blocks (REQUIRED — do NOT skip). Call themetadata action via
discoverUiComponents. Use property types from the widget spec to seedexecute_metadata_action(text →searchQuery, number →"text"). If"number"returnsdiscoverUiComponents, an error, or an empty list, STOP and surface the error verbatim — do not improvise block names from memory, prior runs, or training data. Re-run discover with a differentsuccess: falseonly if the failure is search-query-specific.searchQuery -
Select blocks. Choose one block per widget-spec property, plus structural primitives from Layout Best Practices.
-
Get block schemas (REQUIRED — do NOT skip). Call themetadata action via
getUiComponentSchemasfor the selected blocks. Review property metadata. Ifexecute_metadata_actionreturns all-failure or empty, STOP and surface the error — do not improvise from existing widgets in the project.componentSchemas -
Build the UEM tree (example reads REQUIRED — do NOT skip). First, identify which patterns match the widget spec and read each matching example file from this skill's owndirectory (
examples/):<skill-root>/examples/Pattern in the spec Example to read Single object (no iteration) <skill-root>/examples/single-object.jsonAny list iteration (root-level array, nested list, or list embedded in a single-object widget) <skill-root>/examples/list-with-foreach.jsonConditional rendering ( bound to a boolean)if<skill-root>/examples/conditional.jsonA spec may match multiple patterns (e.g. a list of items where some items render conditionally reads bothandlist-with-foreach.json). Read every matching example, and only those — do not skip the read because the pattern feels familiar.conditional.jsonThen:- Map each widget-spec property to a block property; preserve spec order.
- Decide root iteration: single object → properties directly under root . Collection → wrap repeating block in
tile/column/forEach. SeeforItem.references/widget-meta-directives.md - Bind values with (or
{!$attrs.X}inside{!$item.X}).forEach - For conditional blocks, add on
"if"— only when the schema has a matchingmetaproperty.lightning__booleanType
-
Author. Build the JSON Schema from the widget spec. Fields live one level deep under an
schema.jsonwrapper:attributesjson{ "title": "<Widget Display Name>", "description": "<one line about what the widget shows>", "type": "object", "properties": { "attributes": { "lightning:type": "lightning__objectType", "properties": { "<propertyName>": { "title": "<label>", "description": "<short description>", "lightning:type": "<lightning__textType | lightning__numberType | ...>" } } } } }Required root keys:,title,type: "object"(withproperties.attributesand a nestedlightning:type: "lightning__objectType"map). Seepropertiesfor full primitive type guidance.references/schema-from-lightning-type.md -
Author. See
<widgetName>.uiwidget-meta.xmlfor the exact shape.references/widget-bundle-layout.md -
Resolveand write the bundle. Follow the procedure in
<pkgDir>(references/widget-bundle-layout.md). A widget bundle is a three-file set — all three files must be written in the same step; a bundle with fewer than three files is incomplete and will not deploy.## Resolving <pkgDir>text<pkgDir>/uiWidgets/<widgetName>/<widgetName>.json # widget envelope — UEM tree (primary artifact) <pkgDir>/uiWidgets/<widgetName>/schema.json # attribute contract for the envelope <pkgDir>/uiWidgets/<widgetName>/<widgetName>.uiwidget-meta.xml # UiWidgetBundle registrationEach file has a distinct role:- — the widget envelope with the
<widgetName>.jsonUEM tree. This is the primary artifact;tile/widgetis its companion contract, not a substitute.schema.json - — the JSON Schema for the attributes referenced by
schema.jsonbindings in the envelope.{!$attrs.X} - — the
<widgetName>.uiwidget-meta.xmlelement that registers the bundle for source tracking and deployment.UiWidgetBundle
Write all three before proceeding to self-validation. -
Self-validate. Before reporting, confirm each check below and report each result individually (or
pass). Do not summarize as a single "all passed" line — list every check so a reviewer can spot a silent skip.fail (<reason>)- —
schema-parsesparses as JSON.<pkgDir>/uiWidgets/<widgetName>/schema.json - — root has
schema-root-keys(string),title, andtype: "object"(object) — whereproperties.attributescarriesproperties.attributesand a nestedlightning:type: "lightning__objectType"map. Noproperties.unevaluatedProperties: false - — every leaf under
schema-leaf-typescarries aproperties.attributes.properties. Singular nested inner-class fields appear aslightning:type; the nested shape is not redeclared.lightning__objectType - — every
bindings-resolve(or{!$attrs.X}for nested objects) in{!$attrs.<outerField>.<innerField>}resolves to a property under<widgetName>.jsonschema.json, and everyproperties.attributes.propertiesresolves to a{!$item.X}loop variable defined upstream.forItem - —
body-enveloperoot has<widgetName>.jsonand atype: "lightning__agentforceWidget"object whosecontentBodycarries the UEM tree rooted atwidgetBody. No node in the tree — root or non-root — carries atile/widgetkey.type - —
metaxml-wellformedparses as well-formed XML.<widgetName>.uiwidget-meta.xml - —
metaxml-elementshas root<widgetName>.uiwidget-meta.xmland contains<UiWidgetBundle>(non-empty),<masterLabel>(non-empty), and<description>.<widgetType>JSON</widgetType> - — all three files exist at the resolved
files-presentpath.<pkgDir>/uiWidgets/<widgetName>/
-
解析widget规格——生成有序的列表。来源取决于提供的输入(请参阅输入参数):
{ name, type, required }- 如果编排器传入了→ 根据
lightningTypeSchema推导。references/schema-from-lightning-type.md - 否则 → 直接从用户提示中推断列表(粘贴的JSON负载、枚举字段列表或描述性文本)。
- 如果编排器传入了
-
发现块组件(必填——请勿跳过)。 通过调用
execute_metadata_action元数据操作。使用widget规格中的属性类型作为discoverUiComponents的种子(文本类型→searchQuery,数字类型→"text")。如果"number"返回discoverUiComponents、错误或空列表,请停止操作并直接显示错误信息——不要凭记忆、之前的运行记录或训练数据随意编造块名称。仅当失败是由搜索查询引起时,才使用不同的success: false重新运行发现操作。searchQuery -
选择块组件。 为widget规格中的每个属性选择一个块组件,再加上布局最佳实践中的结构基础组件。
-
获取块组件Schema(必填——请勿跳过)。 通过为所选块组件调用
execute_metadata_action元数据操作。查看属性元数据。如果getUiComponentSchemas返回全失败或空列表,请停止操作并显示错误信息——不要从项目中现有widget进行随意修改。componentSchemas -
构建UEM树(必须阅读示例——请勿跳过)。 首先,确定哪些模式与widget规格匹配,并从此技能自身的目录(
examples/)中读取每个匹配的示例文件:<skill-root>/examples/规格中的模式 要读取的示例 单个对象(无迭代) <skill-root>/examples/single-object.json任何列表迭代(根级数组、嵌套列表或嵌入在单个对象widget中的列表) <skill-root>/examples/list-with-foreach.json条件渲染( 绑定到布尔值)if<skill-root>/examples/conditional.json一个规格可能匹配多个模式(例如,包含条件渲染项的列表需要同时读取和list-with-foreach.json)。请阅读所有匹配的示例,且仅读取这些示例——不要因为觉得模式熟悉而跳过读取步骤。conditional.json然后:- 将每个widget规格属性映射到块属性;保留规格中的顺序。
- 决定根迭代方式: 单个对象→属性直接放在根下。集合→将重复块包装在
tile/column/forEach中。请参阅forItem。references/widget-meta-directives.md - 使用(或在
{!$attrs.X}内使用forEach)绑定值。{!$item.X} - 对于条件块,在中添加
meta——仅当Schema中存在匹配的"if"属性时才添加。lightning__booleanType
-
编写。 根据widget规格构建JSON Schema。字段位于
schema.json包装器下的一级目录中:attributesjson{ "title": "<Widget显示名称>", "description": "<关于此widget展示内容的一行描述>", "type": "object", "properties": { "attributes": { "lightning:type": "lightning__objectType", "properties": { "<propertyName>": { "title": "<标签>", "description": "<简短描述>", "lightning:type": "<lightning__textType | lightning__numberType | ...>" } } } } }必填根键:、title、type: "object"(包含properties.attributes和嵌套的lightning:type: "lightning__objectType"映射)。有关完整的基础类型指南,请参阅properties。references/schema-from-lightning-type.md -
编写。 具体结构请参阅
<widgetName>.uiwidget-meta.xml。references/widget-bundle-layout.md -
解析并写入bundle。 遵循
<pkgDir>中的流程(references/widget-bundle-layout.md)。Widget bundle是一个三文件集合——必须在同一步骤中写入所有三个文件;少于三个文件的bundle不完整,无法部署。## Resolving <pkgDir>text<pkgDir>/uiWidgets/<widgetName>/<widgetName>.json # Widget信封——UEM树(核心产物) <pkgDir>/uiWidgets/<widgetName>/schema.json # 信封的属性契约 <pkgDir>/uiWidgets/<widgetName>/<widgetName>.uiwidget-meta.xml # UiWidgetBundle注册文件每个文件都有明确的作用:- ——包含
<widgetName>.jsonUEM树的Widget信封。这是核心产物;tile/widget是其配套契约,而非替代品。schema.json - ——信封中
schema.json绑定引用的属性对应的JSON Schema。{!$attrs.X} - ——用于注册bundle以进行源跟踪和部署的
<widgetName>.uiwidget-meta.xml元素。UiWidgetBundle
在进行自验证之前,请写入所有三个文件。 -
自验证。 在提交结果之前,请确认以下每项检查,并单独报告结果(或
pass)。请勿总结为单一的“全部通过”——列出每项检查,以便审核者发现遗漏的步骤。fail (<原因>)- ——
schema-parses可解析为JSON。<pkgDir>/uiWidgets/<widgetName>/schema.json - ——根节点包含
schema-root-keys(字符串)、title和type: "object"(对象)——其中properties.attributes包含properties.attributes和嵌套的lightning:type: "lightning__objectType"映射。无properties。unevaluatedProperties: false - ——
schema-leaf-types下的每个叶子节点都包含properties.attributes.properties。单个嵌套内部类字段显示为lightning:type;不重新声明嵌套结构。lightning__objectType - ——
bindings-resolve中的每个<widgetName>.json(或嵌套对象的{!$attrs.X})都能解析到{!$attrs.<outerField>.<innerField>}的schema.json下的属性,且每个properties.attributes.properties都能解析到上游定义的{!$item.X}循环变量。forItem - ——
body-envelope根节点包含<widgetName>.json和type: "lightning__agentforceWidget"对象,其中contentBody包含以widgetBody为根的UEM树。树中的所有节点(根节点和非根节点)均不包含tile/widget键。type - ——
metaxml-wellformed可解析为格式良好的XML。<widgetName>.uiwidget-meta.xml - ——
metaxml-elements的根节点为<widgetName>.uiwidget-meta.xml,且包含非空的<UiWidgetBundle>、非空的<masterLabel>和<description>。<widgetType>JSON</widgetType> - ——所有三个文件都存在于解析后的
files-present路径下。<pkgDir>/uiWidgets/<widgetName>/
Rules / Constraints
规则/约束
| Constraint | Rationale |
|---|---|
Block definitions follow | Runtime resolves blocks by exact definition string |
Never pass | It is a fixed wrapper, not a queryable component |
Always supply | Missing parameters cause hard failure, not partial result |
Every | No invented fields |
No | Vibes' safe-shell filter forces manual approval on these patterns even in Bypass mode. Emit separate commands ( |
| 约束 | 理由 |
|---|---|
块定义遵循 | 运行时通过精确的定义字符串解析块组件 |
请勿将 | 它是固定的包装器,并非可查询的组件 |
调用 | 参数缺失会导致彻底失败,而非部分结果 |
主体中的每个 | 禁止使用虚构字段 |
在任何Bash工具调用中,禁止使用 | Vibes的安全shell过滤器即使在绕过模式下,也会对这些模式强制要求手动审批。请发出单独的命令(如 |
Gotchas
常见问题
| Issue | Resolution |
|---|---|
| Pick a different block from |
Body references | Add |
Output written outside | |
| Use |
| 问题 | 解决方案 |
|---|---|
| 从 |
主体引用了 | 将 |
输出写入到 | |
| 仅当Schema中存在 |
Reference File Index
参考文件索引
| File | When to read |
|---|---|
| For |
| When |
| Folder layout, |
| Single-object pattern (root binding via |
| Any list-iteration case — root-level collections, nested lists, and lists embedded inside a single-object widget (e.g. iterating a |
| Conditional pattern ( |
| 文件 | 阅读场景 |
|---|---|
| 涉及 |
| 当提供 |
| 文件夹布局、 |
| 单个对象模式(通过 |
| 任何列表迭代场景——根级集合、嵌套列表,以及嵌入在单个对象widget中的列表(例如,迭代外部Apex负载中的 |
| 条件模式( |