Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,27 @@ tag: vVERSION

---

## 2.7.0

`2026-04-30`

### @ant-design/x

- 🆕 `XProvider` adds `zeroRuntime` prop to support Zero Runtime CSS-in-JS mode, extracting styles at build time to avoid runtime style injection and improve performance. [#1737](https://github.com/ant-design/x/pull/1737) by [seanparmelee](https://github.com/seanparmelee)

### @ant-design/x-card

- 🆕 Added `resolveActionContextPathRefs` for automatic action context path resolution. Supports both v0.9 and v0.8 formats — when an action is triggered, `{ path }` references in `context` are automatically resolved to actual values from the dataModel and merged with the component's runtime context. [#1887](https://github.com/ant-design/x/pull/1887) by [kimteayon](https://github.com/kimteayon)
- 📖 Added `action-context-resolve` demo documentation for both v0.8 and v0.9 formats. [#1887](https://github.com/ant-design/x/pull/1887) by [kimteayon](https://github.com/kimteayon)

### @ant-design/x-skill

- 🛠 Updated `x-card` skill ACTIONS reference documentation with path reference resolution details and corrected React usage examples. [#1887](https://github.com/ant-design/x/pull/1887) by [kimteayon](https://github.com/kimteayon)

### Others

- 📖 Added search bar to the official website to improve documentation discoverability. [#1831](https://github.com/ant-design/x/pull/1831) by [1uokun](https://github.com/1uokun)

## 2.6.0

`2026-04-17`
Expand Down
21 changes: 21 additions & 0 deletions CHANGELOG.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,27 @@ tag: vVERSION

---

## 2.7.0

`2026-04-30`

### @ant-design/x

- 🆕 XProvider 新增 `zeroRuntime` 属性,支持 Zero Runtime CSS-in-JS 模式,在构建时提取样式,避免运行时样式注入,提升性能。[#1737](https://github.com/ant-design/x/pull/1737) 由 [seanparmelee](https://github.com/seanparmelee) 提交

### @ant-design/x-card

- 🆕 新增 Action 上下文路径自动解析能力(`resolveActionContextPathRefs`),支持 v0.9 和 v0.8 两种格式,触发 action 时自动将 `context` 中的 `{ path }` 引用解析为 dataModel 中的实际值,并与组件运行时传入的 context 合并上报。[#1887](https://github.com/ant-design/x/pull/1887) 由 [kimteayon](https://github.com/kimteayon) 提交
- 📖 新增 v0.8 / v0.9 Action Context 解析示例文档(`action-context-resolve`)。[#1887](https://github.com/ant-design/x/pull/1887) 由 [kimteayon](https://github.com/kimteayon) 提交

### @ant-design/x-skill

- 🛠 更新 `x-card` skill 的 ACTIONS 参考文档,补充 Path 引用自动解析说明及正确的 React 使用示例。[#1887](https://github.com/ant-design/x/pull/1887) 由 [kimteayon](https://github.com/kimteayon) 提交

### 其他

- 📖 官网新增搜索栏,提升文档检索体验。[#1831](https://github.com/ant-design/x/pull/1831) 由 [1uokun](https://github.com/1uokun) 提交

## 2.6.0

`2026-04-17`
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "x-mono",
"version": "2.6.0",
"version": "2.7.0",
Comment thread
kimteayon marked this conversation as resolved.
"private": true,
"scripts": {
"presite": "npm run prestart --workspaces",
Expand Down
2 changes: 1 addition & 1 deletion packages/x-card/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ant-design/x-card",
"version": "2.6.0",
"version": "2.7.0",
"description": "React card loader for dynamic content loading and management",
"keywords": [
"A2UI",
Expand Down
18 changes: 14 additions & 4 deletions packages/x-card/src/A2UI/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import type { Catalog } from './catalog';

// v0.8 specific logic
import { resolvePropsV08, extractDataUpdatesV08, applyDataModelUpdateV08 } from './Card.v0.8';
import type { ActionConfigV08 } from './Card.v0.8';

// v0.9 specific logic
import { resolvePropsV09, extractDataUpdatesV09, applyDataModelUpdateV09 } from './Card.v0.9';
import type { ActionConfigV09 } from './Card.v0.9';

// Shared logic
import {
Expand All @@ -22,13 +24,16 @@ export interface CardProps {
id: string;
}

/** actionConfig 联合类型,兼容 v0.8 和 v0.9 格式 */
type ActionConfig = ActionConfigV08 | ActionConfigV09;

/** Recursively render a single node, child nodes are found via getById */
function renderNode(
nodeId: string,
transformer: ComponentTransformer,
components: Record<string, React.ComponentType<any>>,
dataModel: Record<string, any>,
onAction?: (name: string, context: Record<string, any>, actionConfig?: any) => void,
onAction?: (name: string, context: Record<string, any>, actionConfig?: ActionConfig) => void,
onDataChange?: (path: string, value: any) => void,
catalog?: Catalog,
commandVersion?: 'v0.8' | 'v0.9',
Expand Down Expand Up @@ -56,7 +61,7 @@ interface NodeRendererProps {
transformer: ComponentTransformer;
components: Record<string, React.ComponentType<any>>;
dataModel: Record<string, any>;
onAction?: (name: string, context: Record<string, any>, actionConfig?: any) => void;
onAction?: (name: string, context: Record<string, any>, actionConfig?: ActionConfig) => void;
/** Callback when component writes back to dataModel via onChange, path is the binding path */
onDataChange?: (path: string, value: any) => void;
/** catalog for component validation */
Expand Down Expand Up @@ -329,7 +334,11 @@ const Card: React.FC<CardProps> = ({ id }) => {
* Handler when action is triggered
* Use different extractDataUpdates and resolveActionContext based on version
*/
const handleAction = (name: string, context: Record<string, any>, actionConfig?: any) => {
const handleAction = (
name: string,
context: Record<string, any>,
actionConfig?: ActionConfig,
) => {
// Use different extractDataUpdates based on version
const dataUpdates =
commandVersion === 'v0.9'
Expand Down Expand Up @@ -388,9 +397,10 @@ const Card: React.FC<CardProps> = ({ id }) => {
for (const [key, val] of Object.entries(v09Context)) {
if (isPathObject(val)) {
// 从 dataModel 读取实际值,保留其他属性(如 label),将 path 替换为 value
// 注意:value: actualValue 必须放在 ...rest 之后,防止 rest 中残留的 value 字段覆盖解析结果
const actualValue = getValueByPath(dataModel, (val as { path: string }).path);
Comment thread
kimteayon marked this conversation as resolved.
const { path, ...rest } = val as { path: string; [key: string]: any };
resolvedFromConfig[key] = { value: actualValue, ...rest };
resolvedFromConfig[key] = { ...rest, value: actualValue };
} else {
resolvedFromConfig[key] = val;
}
Expand Down
26 changes: 22 additions & 4 deletions packages/x-card/src/A2UI/Card.v0.8.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,27 @@ import {
validateComponentAgainstCatalog,
} from './utils';

/** v0.8 action.context 中单个条目的类型(正常格式) */
export interface ActionContextItemV08 {
key: string;
value: { path: string } | { literalString: string } | unknown;
}

/** v0.8 action 配置类型 */
export interface ActionConfigV08 {
name?: string;
/** 运行时可能收到非法值,函数内部通过 Array.isArray 防御 */
context?: ActionContextItemV08[] | unknown;
[key: string]: unknown;
}

/** 判断一个值是否为 { literalString: string } 形式的字面字符串对象 */
export function isLiteralStringObject(val: any): val is { literalString: string } {
return val !== null && typeof val === 'object' && typeof val.literalString === 'string';
export function isLiteralStringObject(val: unknown): val is { literalString: string } {
return (
val !== null &&
typeof val === 'object' &&
typeof (val as Record<string, unknown>).literalString === 'string'
);
}

/** 将 props 中的路径值替换为 dataModel 中的真实值(v0.8 版本) */
Expand Down Expand Up @@ -93,7 +111,7 @@ function resolveValueV08(val: any, dataModel: Record<string, any>, isActionConte
* v0.8 格式: action.context 是数组 [{ key, value: { path: string } | literal }]
*/
export function resolveActionContextV08(
action: any,
action: ActionConfigV08 | undefined,
dataModel: Record<string, any>,
): Record<string, any> | undefined {
const context = action?.context;
Expand Down Expand Up @@ -133,7 +151,7 @@ export function resolveActionContextV08(
* @returns 需要更新的数据路径和值的数组
*/
export function extractDataUpdatesV08(
action: any,
action: ActionConfigV08 | undefined,
componentContext: Record<string, any>,
): Array<{ path: string; value: any }> {
const context = action?.context;
Expand Down
21 changes: 19 additions & 2 deletions packages/x-card/src/A2UI/Card.v0.9.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ import {
validateComponentAgainstCatalog,
} from './utils';

/** v0.9 action.event.context 中单个值的类型 */
export type ActionContextValueV09 = { path: string } | unknown;

/** v0.9 action.event 类型 */
export interface ActionEventV09 {
name?: string;
/** 运行时可能收到非法值(数组、字符串、null),函数内部通过类型守卫防御 */
context?: Record<string, unknown> | unknown;
[key: string]: unknown;
}

/** v0.9 action 配置类型 */
export interface ActionConfigV09 {
event?: ActionEventV09;
[key: string]: unknown;
}

/** 将 props 中的路径值替换为 dataModel 中的真实值 */
export function resolvePropsV09(
props: Record<string, any>,
Expand Down Expand Up @@ -117,7 +134,7 @@ function resolveValueV09(val: any, dataModel: Record<string, any>): any {
* v0.9 格式: action.event.context 是对象 { key: { path: string } | literal }
*/
export function resolveActionContextV09(
action: any,
action: ActionConfigV09 | undefined,
dataModel: Record<string, any>,
): Record<string, any> | undefined {
const context = action?.event?.context;
Expand Down Expand Up @@ -147,7 +164,7 @@ export function resolveActionContextV09(
* @returns 需要更新的数据路径和值的数组
*/
export function extractDataUpdatesV09(
action: any,
action: ActionConfigV09 | undefined,
componentContext: Record<string, any>,
): Array<{ path: string; value: any }> {
const context = action?.event?.context;
Expand Down
Loading
Loading