diff --git a/common/changes/@visactor/vtable/feat-react-component-container_2024-05-07-09-28.json b/common/changes/@visactor/vtable/feat-react-component-container_2024-05-07-09-28.json
new file mode 100644
index 000000000..efabbdee6
--- /dev/null
+++ b/common/changes/@visactor/vtable/feat-react-component-container_2024-05-07-09-28.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@visactor/vtable",
+ "comment": "feat: add CustomComponent in react-vtable",
+ "type": "none"
+ }
+ ],
+ "packageName": "@visactor/vtable"
+}
\ No newline at end of file
diff --git a/common/changes/@visactor/vtable/feat-react-component-container_2024-05-15-06-22.json b/common/changes/@visactor/vtable/feat-react-component-container_2024-05-15-06-22.json
new file mode 100644
index 000000000..da8e03133
--- /dev/null
+++ b/common/changes/@visactor/vtable/feat-react-component-container_2024-05-15-06-22.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@visactor/vtable",
+ "comment": "feat: add CustomLayout component in react-vtable",
+ "type": "none"
+ }
+ ],
+ "packageName": "@visactor/vtable"
+}
\ No newline at end of file
diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml
index 984321b4e..357ffd506 100644
--- a/common/config/rush/pnpm-lock.yaml
+++ b/common/config/rush/pnpm-lock.yaml
@@ -180,6 +180,7 @@ importers:
'@types/react': ^18.0.0
'@types/react-dom': ^18.0.0
'@types/react-is': ^17.0.3
+ '@types/react-reconciler': 0.28.8
'@visactor/vchart': 1.11.4
'@visactor/vtable': workspace:*
'@visactor/vutils': ~0.18.9
@@ -201,6 +202,7 @@ importers:
react: ^18.0.0
react-dom: ^18.0.0
react-is: ^18.2.0
+ react-reconciler: 0.29.2
rimraf: 3.0.2
sass: 1.43.5
ts-jest: ^26.0.0
@@ -216,6 +218,7 @@ importers:
'@visactor/vtable': link:../vtable
'@visactor/vutils': 0.18.9
react-is: 18.3.1
+ react-reconciler: 0.29.2_react@18.3.1
devDependencies:
'@arco-design/web-react': 2.60.2_psuonouaqi5wuc37nxyknoubym
'@babel/core': 7.20.12
@@ -232,6 +235,7 @@ importers:
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
'@types/react-is': 17.0.7
+ '@types/react-reconciler': 0.28.8
'@visactor/vchart': 1.11.4
'@vitejs/plugin-react': 3.1.0_vite@3.2.6
axios: 1.7.2
@@ -3401,6 +3405,12 @@ packages:
'@types/react': 17.0.80
dev: true
+ /@types/react-reconciler/0.28.8:
+ resolution: {integrity: sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==}
+ dependencies:
+ '@types/react': 18.3.3
+ dev: true
+
/@types/react/17.0.80:
resolution: {integrity: sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA==}
dependencies:
@@ -11246,6 +11256,17 @@ packages:
/react-is/18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+ /react-reconciler/0.29.2_react@18.3.1:
+ resolution: {integrity: sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==}
+ engines: {node: '>=0.10.0'}
+ peerDependencies:
+ react: ^18.3.1
+ dependencies:
+ loose-envify: 1.4.0
+ react: 18.3.1
+ scheduler: 0.23.2
+ dev: false
+
/react-refresh/0.14.2:
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
engines: {node: '>=0.10.0'}
diff --git a/docs/assets/demo-react/en/component/custom-component.md b/docs/assets/demo-react/en/component/custom-component.md
index eea369764..746dbf023 100644
--- a/docs/assets/demo-react/en/component/custom-component.md
+++ b/docs/assets/demo-react/en/component/custom-component.md
@@ -12,7 +12,6 @@ link: '../guide/Developer_Ecology/react'
The `CustomComponent` component facilitates overlaying external components on React-VTable components.
## Code Example
-
```javascript livedemo template=vtable-react
// import * as ReactVTable from '@visactor/react-vtable';
diff --git a/docs/assets/demo-react/en/custom-layout/cell-custom-component.md b/docs/assets/demo-react/en/custom-layout/cell-custom-component.md
new file mode 100644
index 000000000..69744bbf5
--- /dev/null
+++ b/docs/assets/demo-react/en/custom-layout/cell-custom-component.md
@@ -0,0 +1,301 @@
+---
+category: examples
+group: component
+title: cell custom component
+cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/custom-cell-layout-jsx.png
+order: 1-1
+link: '../guide/Developer_Ecology/react'
+---
+
+# cell custom component
+
+Like customLayout, you can use react components to customize layout. For details, please refer to [Custom Components](../guide/Developer_Ecology/react-custom-component)
+
+## code demo
+
+```javascript livedemo template=vtable-react
+// import * as ReactVTable from '@visactor/react-vtable';
+
+const VGroup = ReactVTable.Group;
+const VText = ReactVTable.Text;
+const VImage = ReactVTable.Image;
+const VTag = ReactVTable.Tag;
+
+const records = [
+ {
+ bloggerId: 1,
+ bloggerName: 'Virtual Anchor Xiaohua',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/flower.jpg',
+ introduction:
+ 'Hi everyone, I am Xiaohua, the virtual host. I am a little fairy who likes games, animation and food. I hope to share happy moments with you through live broadcast.',
+ fansCount: 400,
+ worksCount: 10,
+ viewCount: 5,
+ city: 'Dream City',
+ tags: ['game', 'anime', 'food']
+ },
+ {
+ bloggerId: 2,
+ bloggerName: 'Virtual anchor little wolf',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/wolf.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Little Wolf. I like music, travel and photography, and I hope to explore the beauty of the world with you through live broadcast.',
+ fansCount: 800,
+ worksCount: 20,
+ viewCount: 15,
+ city: 'City of Music',
+ tags: ['music', 'travel', 'photography']
+ },
+ {
+ bloggerId: 3,
+ bloggerName: 'Virtual anchor bunny',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/rabbit.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Xiaotu. I like painting, handicrafts and beauty makeup. I hope to share creativity and fashion with you through live broadcast.',
+ fansCount: 600,
+ worksCount: 15,
+ viewCount: 10,
+ city: 'City of Art',
+ tags: ['painting', 'handmade', 'beauty makeup']
+ },
+ {
+ bloggerId: 4,
+ bloggerName: 'Virtual anchor kitten',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/cat.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual host Kitty. I am a lazy cat who likes dancing, fitness and cooking. I hope to live a healthy and happy life with everyone through the live broadcast.',
+ fansCount: 1000,
+ worksCount: 30,
+ viewCount: 20,
+ city: 'Health City',
+ tags: ['dance', 'fitness', 'cooking']
+ },
+ {
+ bloggerId: 5,
+ bloggerName: 'Virtual anchor Bear',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bear.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual host Xiaoxiong. A little wise man who likes movies, reading and philosophy, I hope to explore the meaning of life with you through live broadcast.',
+ fansCount: 1200,
+ worksCount: 25,
+ viewCount: 18,
+ city: 'City of Wisdom',
+ tags: ['Movie', 'Literature']
+ },
+ {
+ bloggerId: 6,
+ bloggerName: 'Virtual anchor bird',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bird.jpeg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Xiaoniao. I like singing, acting and variety shows. I hope to be happy with everyone through the live broadcast.',
+ fansCount: 900,
+ worksCount: 12,
+ viewCount: 8,
+ city: 'Happy City',
+ tags: ['music', 'performance', 'variety']
+ }
+];
+
+const CustomLayoutComponent = (props) => {
+ const { table, row, col, rect, text } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const record = table.getRecordByRowCol(col, row);
+
+ const [hoverTitle, setHoverTitle] = React.useState(false);
+ const [hoverIcon, setHoverIcon] = React.useState(false);
+ const groupRef = React.useRef(null);
+
+ return (
+
+
+
+
+
+
+ {
+ setHoverTitle(true);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ onMouseLeave={(event) => {
+ setHoverTitle(false);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ >
+ ',
+ boundsPadding: [0, 0, 0, 10],
+ cursor: 'pointer',
+ background: hoverIcon ? {
+ fill: '#ccc',
+ cornerRadius: 5,
+ expandX: 1,
+ expandY: 1
+ } : undefined
+ }}
+
+ onMouseEnter={event => {
+ setHoverIcon(true);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ onMouseLeave={event => {
+ setHoverIcon(false);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ >
+
+
+
+ {record.tags.length
+ ? record.tags.map((str, i) => (
+ //
+
+ ))
+ : null}
+
+
+
+ );
+}
+
+const root = ReactDom.createRoot(document.getElementById(CONTAINER_ID));
+root.render(
+
+
+
+
+
+
+
+
+
+);
+
+// release openinula instance, do not copy
+window.customRelease = () => {
+ root.unmount();
+};
+```
diff --git a/docs/assets/demo-react/en/custom-layout/cell-custom-dom.md b/docs/assets/demo-react/en/custom-layout/cell-custom-dom.md
new file mode 100644
index 000000000..4745ab3d4
--- /dev/null
+++ b/docs/assets/demo-react/en/custom-layout/cell-custom-dom.md
@@ -0,0 +1,204 @@
+---
+category: examples
+group: component
+title: cell custom dom component
+cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/react-vtable-cell-dom-component.jpeg
+order: 1-1
+link: '../guide/Developer_Ecology/react'
+---
+
+# cell custom dom component
+
+Use ArcoDesign in cells. For details, please refer to [Custom Components](../guide/Developer_Ecology/react-custom-component)
+
+## code demo
+
+```javascript livedemo template=vtable-react
+// import * as ReactVTable from '@visactor/react-vtable';
+
+const { useCallback, useRef, useState } = React;
+const { ListTable, ListColumn, Group } = ReactVTable;
+const {
+ Avatar,
+ Comment,
+ Card,
+ Popover,
+ Space,
+ Button,
+ Popconfirm,
+ Message,
+ Notification
+ } = ArcoDesign;
+const { IconHeart, IconMessage, IconStar, IconStarFill, IconHeartFill } = ArcoDesignIcon;
+
+const CommentComponent = (props) => {
+ const { table, row, col, rect, dataValue } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const record = table.getRecordByCell(col, row);
+
+ return (
+
+ }
+ }}
+ >
+ );
+};
+
+const CommentReactComponent = (props) => {
+ const { name } = props;
+ const [like, setLike] = useState();
+ const [star, setStar] = useState();
+ const actions = [
+ ,
+ ,
+
+ ];
+ return (
+
+
Here is the description of this user.
+
+ }
+ >
+ {name.slice(0, 1)}
+
+ }
+ content={
Comment body content.
}
+ datetime="1 hour"
+ style={{ marginTop: 10, marginLeft: 10 }}
+ />
+ );
+};
+
+const OperationComponent = (props) => {
+ const { table, row, col, rect, dataValue } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const record = table.getRecordByCell(col, row);
+
+ return (
+
+ }
+ }}
+ >
+ );
+};
+
+const OperationReactComponent = () => {
+ return (
+
+
+ {
+ Message.info({
+ content: 'ok'
+ });
+ }}
+ onCancel={() => {
+ Message.error({
+ content: 'cancel'
+ });
+ }}
+ >
+
+
+
+ );
+};
+
+function generateRandomString(length) {
+ let result = '';
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+ for (let i = 0; i < length; i++) {
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
+ }
+ return result;
+}
+
+function App() {
+ const records = [];
+ for (let i = 0; i < 50; i++) {
+ records.push({
+ id: i,
+ name: generateRandomString(8)
+ });
+ }
+
+ return (
+ {
+ // eslint-disable-next-line no-undef
+ // (window as any).tableInstance = table;
+ }}
+ ReactDOM={ReactDom}
+ >
+
+
+
+
+
+
+
+
+ );
+}
+
+const root = ReactDom.createRoot(document.getElementById(CONTAINER_ID));
+root.render();
+
+// release react instance, do not copy
+window.customRelease = () => {
+ root.unmount();
+};
+```
diff --git a/docs/assets/demo-react/en/custom-layout/cell-custom-layout-dom.md b/docs/assets/demo-react/en/custom-layout/cell-custom-layout-dom.md
new file mode 100644
index 000000000..706bed9f8
--- /dev/null
+++ b/docs/assets/demo-react/en/custom-layout/cell-custom-layout-dom.md
@@ -0,0 +1,249 @@
+---
+category: examples
+group: component
+title: cell custom component + dom component
+cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/react-vtable-dom-component.gif
+order: 1-1
+link: '../guide/Developer_Ecology/react'
+---
+
+# cell custom component + dom component
+
+Use ArcoDesign in the cell pop-up window. For details, please refer to [Custom Components](../guide/Developer_Ecology/react-custom-component)
+
+## code demo
+
+```javascript livedemo template=vtable-react
+// import * as ReactVTable from '@visactor/react-vtable';
+
+const { useCallback, useRef, useState } = React;
+const { ListTable, ListColumn, Group, Text, Image } = ReactVTable;
+const { Avatar, Card, Space, Typography } = ArcoDesign;
+const { IconThumbUp, IconShareInternal, IconMore } = ArcoDesignIcon;
+const { Meta } = Card;
+
+const UserProfileComponent = (props) => {
+ const { table, row, col, rect, dataValue } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const record = table.getRecordByCell(col, row);
+
+ const [hover, setHover] = useState(false);
+
+ return (
+
+
+ }
+ }}
+ onMouseEnter={(event) => {
+ setHover(true);
+ event.currentTarget.stage.renderNextFrame(); // to do: auto execute in react-vtable
+ }}
+ onMouseLeave={(event) => {
+ setHover(false);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ >
+
+
+
+
+ );
+};
+
+const CardInfo = (props) => {
+ const { bloggerName, bloggerAvatar, introduction, city } = props.record;
+ return props.hover ? (
+
+
+
+ }
+ // actions={[
+ //
+ //
+ // ,
+ //
+ //
+ // ,
+ //
+ //
+ //
+ // ]}
+ >
+
+ {city.slice(0, 1)}
+ {city}
+
+ }
+ title={bloggerName}
+ description={introduction}
+ />
+
+ ) : <>>;
+};
+
+function App() {
+ const records = [
+ {
+ bloggerId: 1,
+ bloggerName: 'Virtual Anchor Xiaohua',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/flower.jpg',
+ introduction:
+ 'Hi everyone, I am Xiaohua, the virtual host. I am a little fairy who likes games, animation and food. I hope to share happy moments with you through live broadcast.',
+ fansCount: 400,
+ worksCount: 10,
+ viewCount: 5,
+ city: 'Dream City',
+ tags: ['game', 'anime', 'food']
+ },
+ {
+ bloggerId: 2,
+ bloggerName: 'Virtual anchor little wolf',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/wolf.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Little Wolf. I like music, travel and photography, and I hope to explore the beauty of the world with you through live broadcast.',
+ fansCount: 800,
+ worksCount: 20,
+ viewCount: 15,
+ city: 'City of Music',
+ tags: ['music', 'travel', 'photography']
+ },
+ {
+ bloggerId: 3,
+ bloggerName: 'Virtual anchor bunny',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/rabbit.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Xiaotu. I like painting, handicrafts and beauty makeup. I hope to share creativity and fashion with you through live broadcast.',
+ fansCount: 600,
+ worksCount: 15,
+ viewCount: 10,
+ city: 'City of Art',
+ tags: ['painting', 'handmade', 'beauty makeup']
+ },
+ {
+ bloggerId: 4,
+ bloggerName: 'Virtual anchor kitten',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/cat.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual host Kitty. I am a lazy cat who likes dancing, fitness and cooking. I hope to live a healthy and happy life with everyone through the live broadcast.',
+ fansCount: 1000,
+ worksCount: 30,
+ viewCount: 20,
+ city: 'Health City',
+ tags: ['dance', 'fitness', 'cooking']
+ },
+ {
+ bloggerId: 5,
+ bloggerName: 'Virtual anchor Bear',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bear.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual host Xiaoxiong. A little wise man who likes movies, reading and philosophy, I hope to explore the meaning of life with you through live broadcast.',
+ fansCount: 1200,
+ worksCount: 25,
+ viewCount: 18,
+ city: 'City of Wisdom',
+ tags: ['Movie', 'Literature']
+ },
+ {
+ bloggerId: 6,
+ bloggerName: 'Virtual anchor bird',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bird.jpeg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Xiaoniao. I like singing, acting and variety shows. I hope to be happy with everyone through the live broadcast.',
+ fansCount: 900,
+ worksCount: 12,
+ viewCount: 8,
+ city: 'Happy City',
+ tags: ['music', 'performance', 'variety']
+ }
+ ];
+
+ return (
+ {
+ // eslint-disable-next-line no-undef
+ // (window as any).tableInstance = table;
+ }}
+ ReactDOM={ReactDom}
+ >
+
+
+
+
+
+
+
+
+ );
+}
+
+const root = ReactDom.createRoot(document.getElementById(CONTAINER_ID));
+root.render();
+
+// release react instance, do not copy
+window.customRelease = () => {
+ root.unmount();
+};
+```
diff --git a/docs/assets/demo-react/en/custom-layout/custom-layout.md b/docs/assets/demo-react/en/custom-layout/custom-layout.md
deleted file mode 100644
index 706e3749f..000000000
--- a/docs/assets/demo-react/en/custom-layout/custom-layout.md
+++ /dev/null
@@ -1,297 +0,0 @@
----
-category: examples
-group: component
-title: custom layout
-cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/custom-cell-layout-jsx.png
-order: 1-1
-link: '../guide/custom_define/custom_layout'
-option: ListTable-columns-text#customLayout
----
-
-# custom layout
-
-You can use jsx in customLayout to customize the layout. For details, please refer to [Custom Layout](../guide/custom_define/custom_layout)
-
-## code demo
-
-```javascript livedemo template=vtable-react
-// import * as ReactVTable from '@visactor/react-vtable';
-
-const VGroup = ReactVTable.VTable.VGroup;
-const VText = ReactVTable.VTable.VText;
-const VImage = ReactVTable.VTable.VImage;
-const VTag = ReactVTable.VTable.VTag;
-
-const records = [
- {
- bloggerId: 1,
- bloggerName: 'Virtual Anchor Xiaohua',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/flower.jpg',
- introduction:
- 'Hi everyone, I am Xiaohua, the virtual host. I am a little fairy who likes games, animation and food. I hope to share happy moments with you through live broadcast.',
- fansCount: 400,
- worksCount: 10,
- viewCount: 5,
- city: 'Dream City',
- tags: ['game', 'anime', 'food']
- },
- {
- bloggerId: 2,
- bloggerName: 'Virtual anchor little wolf',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/wolf.jpg',
- introduction:
- 'Hello everyone, I am the virtual anchor Little Wolf. I like music, travel and photography, and I hope to explore the beauty of the world with you through live broadcast.',
- fansCount: 800,
- worksCount: 20,
- viewCount: 15,
- city: 'City of Music',
- tags: ['music', 'travel', 'photography']
- },
- {
- bloggerId: 3,
- bloggerName: 'Virtual anchor bunny',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/rabbit.jpg',
- introduction:
- 'Hello everyone, I am the virtual anchor Xiaotu. I like painting, handicrafts and beauty makeup. I hope to share creativity and fashion with you through live broadcast.',
- fansCount: 600,
- worksCount: 15,
- viewCount: 10,
- city: 'City of Art',
- tags: ['painting', 'handmade', 'beauty makeup']
- },
- {
- bloggerId: 4,
- bloggerName: 'Virtual anchor kitten',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/cat.jpg',
- introduction:
- 'Hello everyone, I am the virtual host Kitty. I am a lazy cat who likes dancing, fitness and cooking. I hope to live a healthy and happy life with everyone through the live broadcast.',
- fansCount: 1000,
- worksCount: 30,
- viewCount: 20,
- city: 'Health City',
- tags: ['dance', 'fitness', 'cooking']
- },
- {
- bloggerId: 5,
- bloggerName: 'Virtual anchor Bear',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bear.jpg',
- introduction:
- 'Hello everyone, I am the virtual host Xiaoxiong. A little wise man who likes movies, reading and philosophy, I hope to explore the meaning of life with you through live broadcast.',
- fansCount: 1200,
- worksCount: 25,
- viewCount: 18,
- city: 'City of Wisdom',
- tags: ['Movie', 'Literature']
- },
- {
- bloggerId: 6,
- bloggerName: 'Virtual anchor bird',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bird.jpeg',
- introduction:
- 'Hello everyone, I am the virtual anchor Xiaoniao. I like singing, acting and variety shows. I hope to be happy with everyone through the live broadcast.',
- fansCount: 900,
- worksCount: 12,
- viewCount: 8,
- city: 'Happy City',
- tags: ['music', 'performance', 'variety']
- }
-];
-
-const root = ReactDom.createRoot(document.getElementById(CONTAINER_ID));
-root.render(
-
-
- {
- const { table, row, col, rect } = args;
- const { height, width } = rect || table.getCellRect(col, row);
- const record = table.getRecordByRowCol(col, row);
- // const jsx = jsx;
- const container = (
-
-
-
-
-
-
-
- ',
- boundsPadding: [0, 0, 0, 10],
- cursor: 'pointer'
- }}
- stateProxy={stateName => {
- if (stateName === 'hover') {
- return {
- background: {
- fill: '#ccc',
- cornerRadius: 5,
- expandX: 1,
- expandY: 1
- }
- };
- }
- }}
- onMouseEnter={event => {
- event.currentTarget.addState('hover', true, false);
- event.currentTarget.stage.renderNextFrame();
- }}
- onMouseLeave={event => {
- event.currentTarget.removeState('hover', false);
- event.currentTarget.stage.renderNextFrame();
- }}
- >
-
-
-
- {record.tags.length
- ? record.tags.map((str, i) => (
- //
-
- ))
- : null}
-
-
-
- );
-
- // decode(container)
- return {
- rootContainer: container,
- renderDefault: false
- };
- }}
- />
-
-
-
-
-);
-
-// release openinula instance, do not copy
-window.customRelease = () => {
- root.unmount();
-};
-```
diff --git a/docs/assets/demo-react/menu.json b/docs/assets/demo-react/menu.json
index 343675dec..7509032f0 100644
--- a/docs/assets/demo-react/menu.json
+++ b/docs/assets/demo-react/menu.json
@@ -115,10 +115,24 @@
},
"children": [
{
- "path": "custom-layout",
+ "path": "cell-custom-component",
"title": {
- "zh": "自定义布局",
- "en": "custom layout"
+ "zh": "单元格自定义组件",
+ "en": "cell custom component"
+ }
+ },
+ {
+ "path": "cell-custom-layout-dom",
+ "title": {
+ "zh": "单元格自定义组件+dom组件",
+ "en": "cell custom component + dom component"
+ }
+ },
+ {
+ "path": "cell-custom-dom",
+ "title": {
+ "zh": "单元格内dom组件",
+ "en": "cell custom dom component"
}
}
]
diff --git a/docs/assets/demo-react/zh/custom-layout/cell-custom-component.md b/docs/assets/demo-react/zh/custom-layout/cell-custom-component.md
new file mode 100644
index 000000000..f475938f7
--- /dev/null
+++ b/docs/assets/demo-react/zh/custom-layout/cell-custom-component.md
@@ -0,0 +1,301 @@
+---
+category: examples
+group: component
+title: 单元格自定义组件
+cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/custom-cell-layout-jsx.png
+order: 1-1
+link: '../guide/Developer_Ecology/react'
+---
+
+# 单元格自定义组件
+
+同customLayout一样,可以使用react组件进行自定义布局,具体可以参考[自定义组件](../guide/Developer_Ecology/react-custom-component)
+
+## 代码演示
+
+```javascript livedemo template=vtable-react
+// import * as ReactVTable from '@visactor/react-vtable';
+
+const VGroup = ReactVTable.Group;
+const VText = ReactVTable.Text;
+const VImage = ReactVTable.Image;
+const VTag = ReactVTable.Tag;
+
+const records = [
+ {
+ bloggerId: 1,
+ bloggerName: 'Virtual Anchor Xiaohua',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/flower.jpg',
+ introduction:
+ 'Hi everyone, I am Xiaohua, the virtual host. I am a little fairy who likes games, animation and food. I hope to share happy moments with you through live broadcast.',
+ fansCount: 400,
+ worksCount: 10,
+ viewCount: 5,
+ city: 'Dream City',
+ tags: ['game', 'anime', 'food']
+ },
+ {
+ bloggerId: 2,
+ bloggerName: 'Virtual anchor little wolf',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/wolf.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Little Wolf. I like music, travel and photography, and I hope to explore the beauty of the world with you through live broadcast.',
+ fansCount: 800,
+ worksCount: 20,
+ viewCount: 15,
+ city: 'City of Music',
+ tags: ['music', 'travel', 'photography']
+ },
+ {
+ bloggerId: 3,
+ bloggerName: 'Virtual anchor bunny',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/rabbit.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Xiaotu. I like painting, handicrafts and beauty makeup. I hope to share creativity and fashion with you through live broadcast.',
+ fansCount: 600,
+ worksCount: 15,
+ viewCount: 10,
+ city: 'City of Art',
+ tags: ['painting', 'handmade', 'beauty makeup']
+ },
+ {
+ bloggerId: 4,
+ bloggerName: 'Virtual anchor kitten',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/cat.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual host Kitty. I am a lazy cat who likes dancing, fitness and cooking. I hope to live a healthy and happy life with everyone through the live broadcast.',
+ fansCount: 1000,
+ worksCount: 30,
+ viewCount: 20,
+ city: 'Health City',
+ tags: ['dance', 'fitness', 'cooking']
+ },
+ {
+ bloggerId: 5,
+ bloggerName: 'Virtual anchor Bear',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bear.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual host Xiaoxiong. A little wise man who likes movies, reading and philosophy, I hope to explore the meaning of life with you through live broadcast.',
+ fansCount: 1200,
+ worksCount: 25,
+ viewCount: 18,
+ city: 'City of Wisdom',
+ tags: ['Movie', 'Literature']
+ },
+ {
+ bloggerId: 6,
+ bloggerName: 'Virtual anchor bird',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bird.jpeg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Xiaoniao. I like singing, acting and variety shows. I hope to be happy with everyone through the live broadcast.',
+ fansCount: 900,
+ worksCount: 12,
+ viewCount: 8,
+ city: 'Happy City',
+ tags: ['music', 'performance', 'variety']
+ }
+];
+
+const CustomLayoutComponent = (props) => {
+ const { table, row, col, rect, text } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const record = table.getRecordByRowCol(col, row);
+
+ const [hoverTitle, setHoverTitle] = React.useState(false);
+ const [hoverIcon, setHoverIcon] = React.useState(false);
+ const groupRef = React.useRef(null);
+
+ return (
+
+
+
+
+
+
+ {
+ setHoverTitle(true);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ onMouseLeave={(event) => {
+ setHoverTitle(false);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ >
+ ',
+ boundsPadding: [0, 0, 0, 10],
+ cursor: 'pointer',
+ background: hoverIcon ? {
+ fill: '#ccc',
+ cornerRadius: 5,
+ expandX: 1,
+ expandY: 1
+ } : undefined
+ }}
+
+ onMouseEnter={event => {
+ setHoverIcon(true);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ onMouseLeave={event => {
+ setHoverIcon(false);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ >
+
+
+
+ {record.tags.length
+ ? record.tags.map((str, i) => (
+ //
+
+ ))
+ : null}
+
+
+
+ );
+}
+
+const root = ReactDom.createRoot(document.getElementById(CONTAINER_ID));
+root.render(
+
+
+
+
+
+
+
+
+
+);
+
+// release openinula instance, do not copy
+window.customRelease = () => {
+ root.unmount();
+};
+```
diff --git a/docs/assets/demo-react/zh/custom-layout/cell-custom-dom.md b/docs/assets/demo-react/zh/custom-layout/cell-custom-dom.md
new file mode 100644
index 000000000..b08666947
--- /dev/null
+++ b/docs/assets/demo-react/zh/custom-layout/cell-custom-dom.md
@@ -0,0 +1,204 @@
+---
+category: examples
+group: component
+title: 单元格内dom组件
+cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/react-vtable-cell-dom-component.jpeg
+order: 1-1
+link: '../guide/Developer_Ecology/react'
+---
+
+# 单元格内dom组件
+
+在单元格内使用ArcoDesign,具体可以参考[自定义组件](../guide/Developer_Ecology/react-custom-component)
+
+## 代码演示
+
+```javascript livedemo template=vtable-react
+// import * as ReactVTable from '@visactor/react-vtable';
+
+const { useCallback, useRef, useState } = React;
+const { ListTable, ListColumn, Group } = ReactVTable;
+const {
+ Avatar,
+ Comment,
+ Card,
+ Popover,
+ Space,
+ Button,
+ Popconfirm,
+ Message,
+ Notification
+ } = ArcoDesign;
+const { IconHeart, IconMessage, IconStar, IconStarFill, IconHeartFill } = ArcoDesignIcon;
+
+const CommentComponent = (props) => {
+ const { table, row, col, rect, dataValue } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const record = table.getRecordByCell(col, row);
+
+ return (
+
+ }
+ }}
+ >
+ );
+};
+
+const CommentReactComponent = (props) => {
+ const { name } = props;
+ const [like, setLike] = useState();
+ const [star, setStar] = useState();
+ const actions = [
+ ,
+ ,
+
+ ];
+ return (
+
+
Here is the description of this user.
+
+ }
+ >
+ {name.slice(0, 1)}
+
+ }
+ content={
Comment body content.
}
+ datetime="1 hour"
+ style={{ marginTop: 10, marginLeft: 10 }}
+ />
+ );
+};
+
+const OperationComponent = (props) => {
+ const { table, row, col, rect, dataValue } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const record = table.getRecordByCell(col, row);
+
+ return (
+
+ }
+ }}
+ >
+ );
+};
+
+const OperationReactComponent = () => {
+ return (
+
+
+ {
+ Message.info({
+ content: 'ok'
+ });
+ }}
+ onCancel={() => {
+ Message.error({
+ content: 'cancel'
+ });
+ }}
+ >
+
+
+
+ );
+};
+
+function generateRandomString(length) {
+ let result = '';
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+ for (let i = 0; i < length; i++) {
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
+ }
+ return result;
+}
+
+function App() {
+ const records = [];
+ for (let i = 0; i < 50; i++) {
+ records.push({
+ id: i,
+ name: generateRandomString(8)
+ });
+ }
+
+ return (
+ {
+ // eslint-disable-next-line no-undef
+ // (window as any).tableInstance = table;
+ }}
+ ReactDOM={ReactDom}
+ >
+
+
+
+
+
+
+
+
+ );
+}
+
+const root = ReactDom.createRoot(document.getElementById(CONTAINER_ID));
+root.render();
+
+// release react instance, do not copy
+window.customRelease = () => {
+ root.unmount();
+};
+```
diff --git a/docs/assets/demo-react/zh/custom-layout/cell-custom-layout-dom.md b/docs/assets/demo-react/zh/custom-layout/cell-custom-layout-dom.md
new file mode 100644
index 000000000..8c451c2c9
--- /dev/null
+++ b/docs/assets/demo-react/zh/custom-layout/cell-custom-layout-dom.md
@@ -0,0 +1,249 @@
+---
+category: examples
+group: component
+title: 单元格自定义组件+dom组件
+cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/react-vtable-dom-component.gif
+order: 1-1
+link: '../guide/Developer_Ecology/react'
+---
+
+# 单元格自定义组件+dom组件
+
+在单元格弹窗使用ArcoDesign,具体可以参考[自定义组件](../guide/Developer_Ecology/react-custom-component)
+
+## 代码演示
+
+```javascript livedemo template=vtable-react
+// import * as ReactVTable from '@visactor/react-vtable';
+
+const { useCallback, useRef, useState } = React;
+const { ListTable, ListColumn, Group, Text, Image } = ReactVTable;
+const { Avatar, Card, Space, Typography } = ArcoDesign;
+const { IconThumbUp, IconShareInternal, IconMore } = ArcoDesignIcon;
+const { Meta } = Card;
+
+const UserProfileComponent = (props) => {
+ const { table, row, col, rect, dataValue } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const record = table.getRecordByCell(col, row);
+
+ const [hover, setHover] = useState(false);
+
+ return (
+
+
+ }
+ }}
+ onMouseEnter={(event) => {
+ setHover(true);
+ event.currentTarget.stage.renderNextFrame(); // to do: auto execute in react-vtable
+ }}
+ onMouseLeave={(event) => {
+ setHover(false);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ >
+
+
+
+
+ );
+};
+
+const CardInfo = (props) => {
+ const { bloggerName, bloggerAvatar, introduction, city } = props.record;
+ return props.hover ? (
+
+
+
+ }
+ // actions={[
+ //
+ //
+ // ,
+ //
+ //
+ // ,
+ //
+ //
+ //
+ // ]}
+ >
+
+ {city.slice(0, 1)}
+ {city}
+
+ }
+ title={bloggerName}
+ description={introduction}
+ />
+
+ ) : <>>;
+};
+
+function App() {
+ const records = [
+ {
+ bloggerId: 1,
+ bloggerName: 'Virtual Anchor Xiaohua',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/flower.jpg',
+ introduction:
+ 'Hi everyone, I am Xiaohua, the virtual host. I am a little fairy who likes games, animation and food. I hope to share happy moments with you through live broadcast.',
+ fansCount: 400,
+ worksCount: 10,
+ viewCount: 5,
+ city: 'Dream City',
+ tags: ['game', 'anime', 'food']
+ },
+ {
+ bloggerId: 2,
+ bloggerName: 'Virtual anchor little wolf',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/wolf.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Little Wolf. I like music, travel and photography, and I hope to explore the beauty of the world with you through live broadcast.',
+ fansCount: 800,
+ worksCount: 20,
+ viewCount: 15,
+ city: 'City of Music',
+ tags: ['music', 'travel', 'photography']
+ },
+ {
+ bloggerId: 3,
+ bloggerName: 'Virtual anchor bunny',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/rabbit.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Xiaotu. I like painting, handicrafts and beauty makeup. I hope to share creativity and fashion with you through live broadcast.',
+ fansCount: 600,
+ worksCount: 15,
+ viewCount: 10,
+ city: 'City of Art',
+ tags: ['painting', 'handmade', 'beauty makeup']
+ },
+ {
+ bloggerId: 4,
+ bloggerName: 'Virtual anchor kitten',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/cat.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual host Kitty. I am a lazy cat who likes dancing, fitness and cooking. I hope to live a healthy and happy life with everyone through the live broadcast.',
+ fansCount: 1000,
+ worksCount: 30,
+ viewCount: 20,
+ city: 'Health City',
+ tags: ['dance', 'fitness', 'cooking']
+ },
+ {
+ bloggerId: 5,
+ bloggerName: 'Virtual anchor Bear',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bear.jpg',
+ introduction:
+ 'Hello everyone, I am the virtual host Xiaoxiong. A little wise man who likes movies, reading and philosophy, I hope to explore the meaning of life with you through live broadcast.',
+ fansCount: 1200,
+ worksCount: 25,
+ viewCount: 18,
+ city: 'City of Wisdom',
+ tags: ['Movie', 'Literature']
+ },
+ {
+ bloggerId: 6,
+ bloggerName: 'Virtual anchor bird',
+ bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bird.jpeg',
+ introduction:
+ 'Hello everyone, I am the virtual anchor Xiaoniao. I like singing, acting and variety shows. I hope to be happy with everyone through the live broadcast.',
+ fansCount: 900,
+ worksCount: 12,
+ viewCount: 8,
+ city: 'Happy City',
+ tags: ['music', 'performance', 'variety']
+ }
+ ];
+
+ return (
+ {
+ // eslint-disable-next-line no-undef
+ // (window as any).tableInstance = table;
+ }}
+ ReactDOM={ReactDom}
+ >
+
+
+
+
+
+
+
+
+ );
+}
+
+const root = ReactDom.createRoot(document.getElementById(CONTAINER_ID));
+root.render();
+
+// release react instance, do not copy
+window.customRelease = () => {
+ root.unmount();
+};
+```
diff --git a/docs/assets/demo-react/zh/custom-layout/custom-layout.md b/docs/assets/demo-react/zh/custom-layout/custom-layout.md
deleted file mode 100644
index 3f44dc1d8..000000000
--- a/docs/assets/demo-react/zh/custom-layout/custom-layout.md
+++ /dev/null
@@ -1,297 +0,0 @@
----
-category: examples
-group: component
-title: custom layout
-cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/custom-cell-layout-jsx.png
-order: 1-1
-link: '../guide/custom_define/custom_layout'
-option: ListTable-columns-text#customLayout
----
-
-# custom layout
-
-可以在 customLayout 中使用 jsx 进行自定义布局,具体可以参考[自定义布局](../guide/custom_define/custom_layout)
-
-## 代码演示
-
-```javascript livedemo template=vtable-react
-// import * as ReactVTable from '@visactor/react-vtable';
-
-const VGroup = ReactVTable.VTable.VGroup;
-const VText = ReactVTable.VTable.VText;
-const VImage = ReactVTable.VTable.VImage;
-const VTag = ReactVTable.VTable.VTag;
-
-const records = [
- {
- bloggerId: 1,
- bloggerName: 'Virtual Anchor Xiaohua',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/flower.jpg',
- introduction:
- 'Hi everyone, I am Xiaohua, the virtual host. I am a little fairy who likes games, animation and food. I hope to share happy moments with you through live broadcast.',
- fansCount: 400,
- worksCount: 10,
- viewCount: 5,
- city: 'Dream City',
- tags: ['game', 'anime', 'food']
- },
- {
- bloggerId: 2,
- bloggerName: 'Virtual anchor little wolf',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/wolf.jpg',
- introduction:
- 'Hello everyone, I am the virtual anchor Little Wolf. I like music, travel and photography, and I hope to explore the beauty of the world with you through live broadcast.',
- fansCount: 800,
- worksCount: 20,
- viewCount: 15,
- city: 'City of Music',
- tags: ['music', 'travel', 'photography']
- },
- {
- bloggerId: 3,
- bloggerName: 'Virtual anchor bunny',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/rabbit.jpg',
- introduction:
- 'Hello everyone, I am the virtual anchor Xiaotu. I like painting, handicrafts and beauty makeup. I hope to share creativity and fashion with you through live broadcast.',
- fansCount: 600,
- worksCount: 15,
- viewCount: 10,
- city: 'City of Art',
- tags: ['painting', 'handmade', 'beauty makeup']
- },
- {
- bloggerId: 4,
- bloggerName: 'Virtual anchor kitten',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/cat.jpg',
- introduction:
- 'Hello everyone, I am the virtual host Kitty. I am a lazy cat who likes dancing, fitness and cooking. I hope to live a healthy and happy life with everyone through the live broadcast.',
- fansCount: 1000,
- worksCount: 30,
- viewCount: 20,
- city: 'Health City',
- tags: ['dance', 'fitness', 'cooking']
- },
- {
- bloggerId: 5,
- bloggerName: 'Virtual anchor Bear',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bear.jpg',
- introduction:
- 'Hello everyone, I am the virtual host Xiaoxiong. A little wise man who likes movies, reading and philosophy, I hope to explore the meaning of life with you through live broadcast.',
- fansCount: 1200,
- worksCount: 25,
- viewCount: 18,
- city: 'City of Wisdom',
- tags: ['Movie', 'Literature']
- },
- {
- bloggerId: 6,
- bloggerName: 'Virtual anchor bird',
- bloggerAvatar: 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/custom-render/bird.jpeg',
- introduction:
- 'Hello everyone, I am the virtual anchor Xiaoniao. I like singing, acting and variety shows. I hope to be happy with everyone through the live broadcast.',
- fansCount: 900,
- worksCount: 12,
- viewCount: 8,
- city: 'Happy City',
- tags: ['music', 'performance', 'variety']
- }
-];
-
-const root = ReactDom.createRoot(document.getElementById(CONTAINER_ID));
-root.render(
-
-
- {
- const { table, row, col, rect } = args;
- const { height, width } = rect || table.getCellRect(col, row);
- const record = table.getRecordByRowCol(col, row);
- // const jsx = jsx;
- const container = (
-
-
-
-
-
-
-
- ',
- boundsPadding: [0, 0, 0, 10],
- cursor: 'pointer'
- }}
- stateProxy={stateName => {
- if (stateName === 'hover') {
- return {
- background: {
- fill: '#ccc',
- cornerRadius: 5,
- expandX: 1,
- expandY: 1
- }
- };
- }
- }}
- onMouseEnter={event => {
- event.currentTarget.addState('hover', true, false);
- event.currentTarget.stage.renderNextFrame();
- }}
- onMouseLeave={event => {
- event.currentTarget.removeState('hover', false);
- event.currentTarget.stage.renderNextFrame();
- }}
- >
-
-
-
- {record.tags.length
- ? record.tags.map((str, i) => (
- //
-
- ))
- : null}
-
-
-
- );
-
- // decode(container)
- return {
- rootContainer: container,
- renderDefault: false
- };
- }}
- />
-
-
-
-
-);
-
-// release openinula instance, do not copy
-window.customRelease = () => {
- root.unmount();
-};
-```
diff --git a/docs/assets/guide/en/Developer_Ecology/react-custom-component.md b/docs/assets/guide/en/Developer_Ecology/react-custom-component.md
new file mode 100644
index 000000000..45487648f
--- /dev/null
+++ b/docs/assets/guide/en/Developer_Ecology/react-custom-component.md
@@ -0,0 +1,235 @@
+# React-VTable custom components
+
+## Custom cell components
+
+To help react developers quickly implement custom cell content, React-VTable provides the ability to encapsulate components and use them in cells.
+
+### Component usage
+
+Custom cell components are encapsulated based on [custom layout](../custom_define/custom_layout), and their usage is similar to custom layout. To use components in `ListColumn`, custom components need to pass in the `role` attribute to identify the component as a custom cell component; the `custom-layout` component will take effect in the table content part, and the `header-custom-layout` component will take effect in the table header part. There can be at most one `custom-layout` component in each column, and at most one `header-custom-layout` component.
+
+```tsx
+
+
+
+
+
+ // ......
+
+```
+
+### Component encapsulation
+
+#### Default properties
+
+In the component, in addition to user-defined properties, like custom layouts, react-vtable also provides some default properties for components to use
+
+```tsx
+interface CustomLayoutProps {
+ table: ListTable; // 表格实例
+ row: number; // 行号
+ col: number; // 列号
+ value: FieldData; // 单元格展示数据
+ dataValue: FieldData; // 单元格原始数据
+ rect?: RectProps; // 单元格布局信息
+}
+const CustomLayoutComponent = (props: CustomLayoutProps & UserProps) => {
+ const { table, row, col, rect, text } = props;
+ // ......
+}
+```
+
+#### Label
+
+The label returned by the component must be based on the element label provided by react-vtable (HTML tags or DOM react components cannot be used directly. If you need to use them, please refer to the next section)
+
+```tsx
+import { Group, Text } from '@visactor/react-vtable';
+
+const CustomLayoutComponent = (props: CustomLayoutFunctionArg & { text: string }) => {
+ const { table, row, col, rect, text } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const [hover, setHover] = useState(false);
+
+ const fieldData = [
+ {
+ value: 'a',
+ label: 'a'
+ },
+ {
+ value: 'b',
+ label: 'b'
+ }
+ ];
+
+ const groupRef = useRef(null);
+
+ return (
+
+ {fieldData.map(item => {
+ return (
+ {
+ // eslint-disable-next-line no-console, no-undef
+ console.log('groupRef', groupRef.current);
+ setHover(true);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ onMouseLeave={(event: any) => {
+ setHover(false);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ />
+ );
+ })}
+ {hover && (
+
+ )}
+
+ );
+};
+```
+
+Basic primitives:
+
+* Text
+* Rect
+* Image
+* Line
+* Arc
+* Circle
+* Group
+
+Basic components:
+
+* Tag
+* Radio
+* Checkbox Checkbox
+
+For specific configuration properties, please refer to [`VRender element configuration`](https://visactor.io/vrender/option/Group), and for specific usage and layout, please refer to [custom layout](../custom_define/custom_layout), [reference example](../../demo-react/component/custom-layout).
+
+
+
+
+
+#### Use DOM react components
+
+If you need to use DOM react components in components, you can specify the `react` attribute in the `attribute` property of the element component and pass the react component as the `element` property:
+
+```tsx
+
+ }
+ }}
+ onMouseEnter={(event) => {
+ setHover(true);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ onMouseLeave={(event) => {
+ setHover(false);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+>
+// ...
+
+```
+
+
+
+
+
+The following properties are also supported in react:
+* `pointerEvents` whether to respond to mouse events
+* `container` Container, used to limit the component display area in the table when scrolling. If you need to limit the component display in the table content area, you need to specify it as `table.bodyDomContainer`; if you need to limit the component display in the table header area, you need to specify it as `table.headerDomContainer`; if it is a pop-up window or menu component, you do not need to configure this property
+* `anchorType` Anchor type, used to specify the anchor position of the upper left corner of the component relative to the cell
+ * 'top'
+ * 'bottom'
+ * 'left'
+ * 'right'
+ * 'top-right'
+ * 'top-left'
+ * 'bottom-right'
+ * 'bottom-left'
+ * 'center'
+
+We recommend that users use the meta tags provided by react-vtable for the content displayed in the cell. For pop-ups, menus and other components triggered in the cell, you can use DOM react components. This is the best performance solution. [Reference example](../../demo-react/component/custom-layout).
+
+If you need to display content in a cell, use DOM react components. You need to specify `react.container` according to the restrictions on components displayed in the table content area. It should be noted that this method requires frequent updates of component-related DOM, which will have a certain impact on performance. You can refer to [custom layout](../custom_define/custom_layout). We strongly recommend that the content components in the cell use the meta tags provided by react-vtable, which is the best solution for performance.
+
+## Custom external components
+
+In order to facilitate the overlay of external components on the React-VTable component, React-VTable provides the `CustomComponent` tool component, which allows you to quickly locate external components in the table, and can be used to quickly implement functional components such as pop-ups and menus.
+
+```jsx
+
+
+
+
+
+```
+
+Among them, `CustomComponent` is used as a container to position in the table and automatically match the size (based on the anchored cell). There are two specific ways to use it:
+
+1. Absolute positioning
+
+For absolute positioning, you need to specify `displayMode` as `position`, and you need to specify `x` and `y` attributes to position the container to the specified pixel position in the table (based on the upper left corner). The `width` and `height` attributes specify the pixel size of the container.
+
+2. Relative positioning
+
+For relative positioning, you need to specify `displayMode` as `cell`, the container is positioned relative to the cell, the `col` and `row` attributes are used to specify the anchored cell coordinates, the `anchor` attribute specifies the anchor position of the container relative to the cell, the `dx` and `dy` attributes specify the offset of the container relative to the anchored cell, and the `width` and `height` attributes specify the size of the container. The `dx` `dy` `width` and `height` attributes all support units of pixels or percentages. When the percentage is calculated relative to the size of the cell.
+
+### API
+
+```ts
+interface CustomComponentProps {
+ children: React.ReactNode;
+ displayMode: 'position' | 'cell'; // Positioning mode
+ col?: number; // Anchored column coordinates
+ row?: number; // Anchored row coordinates
+ anchor?:
+ | 'top-left'
+ | 'top-center'
+ | 'top-right'
+ | 'middle-left'
+ | 'middle-center'
+ | 'middle-right'
+ | 'bottom-left'
+ | 'bottom-center'
+ | 'bottom-right'; // Anchored position
+ dx?: number | string; // x-direction offset
+ dy?: number | string; // y-direction offset
+ width?: number | string; // container width
+ height?: number | string; // container height
+}
+```
+
+Custom external component demo: [custom component demo](../../demo-react/component/custom-component)
\ No newline at end of file
diff --git a/docs/assets/guide/en/Developer_Ecology/react.md b/docs/assets/guide/en/Developer_Ecology/react.md
index 604ae2906..23c855849 100644
--- a/docs/assets/guide/en/Developer_Ecology/react.md
+++ b/docs/assets/guide/en/Developer_Ecology/react.md
@@ -176,7 +176,6 @@ return (
);
```
-
Grammatical label demo: [PivotTable demo](../../demo-react/grammatical-tag/pivot-table) [PivotChart demo](../../demo-react/grammatical-tag/pivot-chart)
#### Components outside the table
@@ -279,52 +278,3 @@ function App() {
```
For detailed description of the event, please refer to: [Event Introduction](../../guide/Event/event_list)
-
-## Custom component
-
-In order to facilitate the superposition of external components on the React-VTable component, React-VTable provides a `CustomComponent` tool component to quickly locate external components into the table.
-
-```jsx
-
-
-
-
-
-```
-
-Among them, `CustomComponent` is used as a container for positioning in the table and automatically matching the size (based on anchored cells). There are two ways to use it:
-
-1. Absolute positioning
-
- For absolute positioning, you need to specify `displayMode` as `position`, `x` and `y` attributes, which are used to position the container to the specified pixel position in the table (based on the upper left corner), `width` and `height `property specifies the pixel dimensions of the container.
-
-2. Relative positioning
-
- For relative positioning, you need to specify `displayMode` as `cell`, the container is positioned relative to the cell, the `col` and `row` attributes are used to specify the anchored cell coordinates, and the `anchor` attribute specifies the container relative to the cell. The anchor position, `dx` and `dy` attributes specify the offset of the container relative to the anchor cell, and the `width` and `height` properties specify the size of the container, where `dx` `dy` `width` and The `height` attribute supports units of pixels or percentages. When it is a percentage, it is calculated relative to the size of the cell.
-
-### API
-
-```ts
-interface CustomComponentProps {
- children: React.ReactNode;
- displayMode: 'position' | 'cell'; // positioning method
- col?: number; // anchored column coordinates
- row?: number; // anchored row coordinates
- anchor?:
- | 'top-left'
- | 'top-center'
- | 'top-right'
- | 'middle-left'
- | 'middle-center'
- | 'middle-right'
- | 'bottom-left'
- | 'bottom-center'
- | 'bottom-right'; // anchored position
- dx?: number | string; // offset in x direction
- dy?: number | string; // offset in y direction
- width?: number | string; // container width
- height?: number | string; // container height
-}
-```
-
-[custom component demo](../../demo-react/component/custom-component)
diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json
index c8b44d150..09a36a953 100644
--- a/docs/assets/guide/menu.json
+++ b/docs/assets/guide/menu.json
@@ -595,6 +595,13 @@
"en": "React-VTable"
}
},
+ {
+ "path": "react-custom-component",
+ "title": {
+ "zh": "React自定义组件",
+ "en": "React Custom Component"
+ }
+ },
{
"path": "openinula",
"title": {
diff --git a/docs/assets/guide/zh/Developer_Ecology/react-custom-component.md b/docs/assets/guide/zh/Developer_Ecology/react-custom-component.md
new file mode 100644
index 000000000..b9fae0166
--- /dev/null
+++ b/docs/assets/guide/zh/Developer_Ecology/react-custom-component.md
@@ -0,0 +1,235 @@
+# React-VTable自定义组件
+
+## 自定义单元格组件
+
+为了方便react开发者快速实现自定义单元格内容,React-VTable 提供了封装组件并在单元格中使用的能力。
+
+### 组件用法
+
+自定义单元格组件在[自定义布局](../custom_define/custom_layout)的基础上封装而成,用法类似于自定义布局。在`ListColumn`中使用组件,自定义组件需要传入`role`属性,用于标识该组件为自定义单元格组件;其中`custom-layout`组件会在表格内容部分生效,`header-custom-layout`组件会在表格表头部分生效。每列中最多只能有一个`custom-layout`组件,最多只能有一个`header-custom-layout`组件。
+
+```tsx
+
+
+
+
+
+ // ......
+
+```
+
+### 组件封装
+
+#### 默认属性
+
+在组件中,除了用户定义的属性外,与自定义布局一样,react-vtable还提供了一些默认属性供组件使用
+
+```tsx
+interface CustomLayoutProps {
+ table: ListTable; // 表格实例
+ row: number; // 行号
+ col: number; // 列号
+ value: FieldData; // 单元格展示数据
+ dataValue: FieldData; // 单元格原始数据
+ rect?: RectProps; // 单元格布局信息
+}
+const CustomLayoutComponent = (props: CustomLayoutProps & UserProps) => {
+ const { table, row, col, rect, text } = props;
+ // ......
+}
+```
+
+#### 标签
+
+组件返回的标签,必须是基于react-vtable提供的图元标签(不可以直接使用HTML标签或DOM react组件,如果需要使用,请参考下一节)
+
+```tsx
+import { Group, Text } from '@visactor/react-vtable';
+
+const CustomLayoutComponent = (props: CustomLayoutFunctionArg & { text: string }) => {
+ const { table, row, col, rect, text } = props;
+ if (!table || row === undefined || col === undefined) {
+ return null;
+ }
+ const { height, width } = rect || table.getCellRect(col, row);
+ const [hover, setHover] = useState(false);
+
+ const fieldData = [
+ {
+ value: 'a',
+ label: 'a'
+ },
+ {
+ value: 'b',
+ label: 'b'
+ }
+ ];
+
+ const groupRef = useRef(null);
+
+ return (
+
+ {fieldData.map(item => {
+ return (
+ {
+ // eslint-disable-next-line no-console, no-undef
+ console.log('groupRef', groupRef.current);
+ setHover(true);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ onMouseLeave={(event: any) => {
+ setHover(false);
+ event.currentTarget.stage.renderNextFrame();
+ }}
+ />
+ );
+ })}
+ {hover && (
+
+ )}
+
+ );
+};
+```
+
+基础图元:
+
+* Text 文字
+* Rect 矩形
+* Image 图片
+* Line 线
+* Arc 弧形
+* Circle 圆
+* Group 图元组
+
+基础组件:
+
+* Tag 文本标签
+* Radio 单选框
+* Checkbox 复选框
+
+具体配置属性可以参考[`VRender图元配置`](https://visactor.io/vrender/option/Group),具体使用和布局可以参考[自定义布局](../custom_define/custom_layout),[参考示例](../../demo-react/component/custom-layout)。
+
+