Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
572 changes: 0 additions & 572 deletions .codefuse/skills/components/SKILL.md

This file was deleted.

4 changes: 4 additions & 0 deletions README-zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@

`@ant-design/x-markdown` 旨在提供流式友好、强拓展性和高性能的 Markdown 渲染器。提供流式渲染公式、代码高亮、mermaid 等能力,详情点击[这里](packages/x-markdown/README-zh_CN.md)。

## 🎴 动态卡片渲染器

`@ant-design/x-card` 是一个基于 A2UI 协议的动态卡片渲染组件,让 AI Agent 能够通过结构化的 JSON 消息流,动态构建和渲染交互式界面。支持流式渲染、数据绑定和响应式更新,详情点击[这里](packages/x-card/README.md)。

## 🚀 Skill

`@ant-design/x-skill` 是专为 Ant Design X 打造的智能技能库,提供了一系列精心设计的 Agent 技能。这些技能能够显著提升开发效率,帮助您快速构建高质量的 AI 对话应用,并有效解决开发过程中遇到的各种问题,详情点击[这里](packages/x-skill/README-zh_CN.md)。
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ Build excellent AI interfaces and pioneer intelligent new experiences.

`@ant-design/x-markdown` aims to provide a streaming-friendly, highly extensible, and high-performance Markdown renderer. It supports streaming rendering of formulas, code highlighting, mermaid, and more. See details [here](packages/x-markdown/README.md).

## 🎴 Dynamic Card Renderer

`@ant-design/x-card` is a dynamic card rendering component based on the A2UI protocol, enabling AI Agents to dynamically build and render interactive interfaces through structured JSON message streams. It supports streaming rendering, data binding, and reactive updates. See details [here](packages/x-card/README.md).

## 🚀 Skill

`@ant-design/x-skill` is an intelligent skill library specially designed for Ant Design X, providing a series of carefully designed Agent skills. These skills can significantly improve development efficiency, help you quickly build high-quality AI conversation applications, and effectively solve various problems encountered during development. See details [here](packages/x-skill/README.md).
Expand Down
38 changes: 38 additions & 0 deletions packages/x-card/.fatherrc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { defineConfig } from 'father';

export default defineConfig({
plugins: ['@rc-component/father-plugin'],
targets: {
chrome: 80,
},
esm: {
input: 'src',
ignores: ['**/demo/**', '**/__tests__/**'],
},
cjs: {
input: 'src/',
ignores: ['**/demo/**', '**/__tests__/**'],
},
umd: {
entry: 'src/index.ts',
name: 'XCard',
output: {
path: 'dist/',
filename: 'x-card',
},
sourcemap: true,
generateUnminified: true,
externals: {
react: {
root: 'React',
commonjs: 'react',
commonjs2: 'react',
},
'react-dom': {
root: 'ReactDOM',
commonjs: 'react-dom',
commonjs2: 'react-dom',
},
},
},
});
73 changes: 73 additions & 0 deletions packages/x-card/.jest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const compileModules = [
'@rc-component',
'react-sticky-box',
'rc-tween-one',
'@babel',
'@ant-design',
'countup.js',
'.pnpm',
];

const resolve = (p) => require.resolve(`@ant-design/tools/lib/jest/${p}`);

const ignoreList = [];

// cnpm use `_` as prefix
['', '_'].forEach((prefix) => {
compileModules.forEach((module) => {
ignoreList.push(`${prefix}${module}`);
});
});

const transformIgnorePatterns = [
// Ignore modules without es dir.
// Update: @babel/runtime should also be transformed
`[/\\\\]node_modules[/\\\\](?!${ignoreList.join('|')})[^/\\\\]+?[/\\\\](?!(es)[/\\\\])`,
];

function getTestRegex(libDir) {
if (['dist', 'lib', 'es', 'dist-min'].includes(libDir)) {
return 'demo\\.test\\.(j|t)sx?$';
}
return '.*\\.test\\.(j|t)sx?$';
}

module.exports = {
verbose: true,
testEnvironment: '@happy-dom/jest-environment',
setupFiles: ['./tests/setup.ts'],
setupFilesAfterEnv: ['@testing-library/jest-dom'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'md'],
modulePathIgnorePatterns: [],
moduleNameMapper: {
'\\.(css|less)$': 'identity-obj-proxy',
},
testPathIgnorePatterns: ['/node_modules/', 'dekko', 'node', 'image.test.js', 'image.test.ts'],
transform: {
'\\.tsx?$': resolve('codePreprocessor'),
'\\.(m?)js$': resolve('codePreprocessor'),
'\\.md$': resolve('demoPreprocessor'),
'\\.(jpg|png|gif|svg)$': resolve('imagePreprocessor'),
},
testRegex: getTestRegex(process.env.LIB_DIR),
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/**/demo/**',
'!src/**/__tests__/**',
'!src/version.ts',
'!src/index.ts', // 纯重导出文件
'!src/A2UI/types/**', // 纯类型文件
],
transformIgnorePatterns,
globals: {
'ts-jest': {
tsConfig: './tsconfig.json',
},
},
testEnvironmentOptions: {
url: 'http://localhost/x-card',
},
bail: true,
maxWorkers: '50%',
};
4 changes: 4 additions & 0 deletions packages/x-card/.lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"*.{ts,tsx}": ["biome lint --fix"],
"*.{ts,tsx,less,md}": ["prettier --write"]
}
184 changes: 184 additions & 0 deletions packages/x-card/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# @ant-design/x-card

React card loader for dynamic content loading and management.

## Features

- 🚀 **Dynamic Loading**: Load cards asynchronously with configurable concurrency
- 🔄 **Retry Mechanism**: Automatic retry with exponential backoff
- ⚡ **Performance**: Optimized for large datasets with virtual scrolling support
- 🎨 **Customizable**: Fully customizable card rendering and loading states
- 📱 **Responsive**: Mobile-friendly responsive design
- 🔧 **TypeScript**: Full TypeScript support

## Installation

```bash
npm install @ant-design/x-card
# or
yarn add @ant-design/x-card
# or
pnpm add @ant-design/x-card
```

## Usage

### Basic Usage

```tsx
import React from 'react';
import { CardLoader } from '@ant-design/x-card';

const App = () => {
const cards = [
{
id: '1',
title: 'Card 1',
content: 'This is card content',
},
{
id: '2',
title: 'Card 2',
content: 'Another card content',
},
];

return <CardLoader cards={cards} />;
};
```

### Advanced Usage

```tsx
import React from 'react';
import { CardLoader, useCardLoader } from '@ant-design/x-card';

const App = () => {
const { state, actions } = useCardLoader({
config: {
maxConcurrent: 5,
retryCount: 3,
timeout: 10000,
},
customLoader: async (card) => {
// Custom loading logic
const response = await fetch(`/api/cards/${card.id}`);
const data = await response.json();
return data.content;
},
});

React.useEffect(() => {
actions.loadCards([
{ id: '1', title: 'Dynamic Card 1' },
{ id: '2', title: 'Dynamic Card 2' },
]);
}, []);

return (
<CardLoader
cards={state.cards}
renderLoading={(card) => <div>Loading {card.title}...</div>}
renderError={(error, card) => <div>Error: {error.message}</div>}
/>
);
};
```

### Using Hooks

```tsx
import React from 'react';
import { useCardLoader } from '@ant-design/x-card';

const App = () => {
const { state, actions } = useCardLoader();

const addNewCard = () => {
actions.addCard({
id: Date.now().toString(),
title: 'New Card',
content: 'Dynamic content',
});
};

return (
<div>
<button onClick={addNewCard}>Add Card</button>
{state.cards.map((card) => (
<div key={card.id}>
<h3>{card.title}</h3>
<p>{card.content}</p>
</div>
))}
</div>
);
};
```

## API

### CardLoader Props

| Property | Type | Default | Description |
| ---------------- | ------------------ | ------- | ----------------------------- |
| cards | CardLoaderConfig[] | [] | Array of card configurations |
| config | CardLoaderConfig | - | Loader configuration |
| customLoader | function | - | Custom card loading function |
| renderEmpty | function | - | Custom empty state renderer |
| renderLoading | function | - | Custom loading state renderer |
| renderError | function | - | Custom error state renderer |
| onLoadingChange | function | - | Loading state change callback |
| onCardLoad | function | - | Card load success callback |
| onCardError | function | - | Card load error callback |
| onAllCardsLoaded | function | - | All cards loaded callback |

### CardLoaderConfig

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| id | string | - | Unique card identifier |
| title | string | - | Card title |
| content | ReactNode | - | Card content |
| type | 'default' \| 'info' \| 'success' \| 'warning' \| 'error' | 'default' | Card type |
| loading | boolean | false | Loading state |
| closable | boolean | false | Whether card can be closed |
| size | 'small' \| 'middle' \| 'large' | 'middle' | Card size |
| disabled | boolean | false | Whether card is disabled |
| className | string | - | Custom CSS class |
| style | CSSProperties | - | Custom inline style |
| extra | ReactNode | - | Extra content in card header |

### useCardLoader Hook

Returns an object with:

- `state`: Current loader state
- `actions`: Available actions
- `addCard(card)`: Add a new card
- `removeCard(id)`: Remove a card
- `updateCard(id, updates)`: Update a card
- `reloadCard(id)`: Reload a card
- `clearCards()`: Clear all cards
- `getCardState(id)`: Get card state
- `loadCards(cards)`: Load multiple cards

## Development

```bash
# Install dependencies
npm install

# Start development
npm run start

# Run tests
npm test

# Build
npm run compile
```

## License

MIT
66 changes: 66 additions & 0 deletions packages/x-card/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@ant-design/x-card",
"version": "2.3.0-beta.2",
"description": "React card loader for dynamic content loading and management",
"keywords": [
"A2UI",
"loader",
"react",
"ant-design"
],
"homepage": "https://x.ant.design/x-card",
"bugs": {
"url": "https://github.com/ant-design/x/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/ant-design/x"
},
"license": "MIT",
"sideEffects": false,
"main": "lib/index.js",
"module": "es/index.js",
"typings": "es/index.d.ts",
"files": [
"dist",
"es",
"lib"
],
"scripts": {
"compile": "father build",
"prepublishOnly": "tsx ../../scripts/pre-publish.ts x-card",
"tsc": "tsc --noEmit",
"lint": "npm run version && npm run tsc && npm run lint:script && npm run lint:md",
"lint:md": "remark . -f -q",
"predist": "npm run prestart",
"prestart": "npm run version",
"pretest": "npm run prestart",
"precompile": "npm run prestart",
"lint:script": "biome lint",
"test": "jest --config .jest.js --no-cache --collect-coverage",
"coverage": "jest --config .jest.js --no-cache --collect-coverage --coverage",
"version": "tsx scripts/generate-version.ts",
"test:dekko": "tsx ./tests/dekko/index.test.ts",
"clean": "rm -rf es lib coverage dist",
"test:package-diff": "antd-tools run package-diff"
},
"dependencies": {
"@ant-design/icons": "^6.0.0",
"@babel/runtime": "^7.25.6",
"classnames": "^2.5.1",
"rc-util": "^5.43.0"
},
"devDependencies": {
"@types/react": "^19.0.2",
"@types/react-dom": "^19.0.2",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"peerDependencies": {
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
}
}
Loading
Loading