feffery_antd_components 0.4.3-rc7 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feffery_antd_components",
3
- "version": "0.4.3-rc7",
3
+ "version": "0.4.3",
4
4
  "description": "Best implementation of Antd components in Plotly Dash.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -71,12 +71,30 @@
71
71
  "react-docgen": "^5.4.3",
72
72
  "react-dom": "^18.3.1",
73
73
  "style-loader": "^0.23.1",
74
- "styled-jsx": "^3.2.1",
74
+ "styled-jsx": "^4.0.0",
75
75
  "webpack": "4.36.1",
76
76
  "webpack-bundle-analyzer": "^4.7.0",
77
77
  "webpack-cli": "^3.3.6",
78
78
  "webpack-serve": "3.1.0"
79
79
  },
80
+ "overrides": {
81
+ "@ant-design/charts": {
82
+ "@ant-design/icons": "$@ant-design/icons",
83
+ "antd": "$antd"
84
+ },
85
+ "react-fast-marquee": {
86
+ "react": "$react",
87
+ "react-dom": "$react-dom"
88
+ },
89
+ "react-highlight-words": {
90
+ "react": "$react",
91
+ "react-dom": "$react-dom"
92
+ },
93
+ "react-text-loop": {
94
+ "react": "$react",
95
+ "react-dom": "$react-dom"
96
+ }
97
+ },
80
98
  "babel": {
81
99
  "presets": [
82
100
  "@babel/preset-react",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feffery_antd_components",
3
- "version": "0.4.3-rc7",
3
+ "version": "0.4.3",
4
4
  "description": "Best implementation of Antd components in Plotly Dash.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -71,12 +71,30 @@
71
71
  "react-docgen": "^5.4.3",
72
72
  "react-dom": "^18.3.1",
73
73
  "style-loader": "^0.23.1",
74
- "styled-jsx": "^3.2.1",
74
+ "styled-jsx": "^4.0.0",
75
75
  "webpack": "4.36.1",
76
76
  "webpack-bundle-analyzer": "^4.7.0",
77
77
  "webpack-cli": "^3.3.6",
78
78
  "webpack-serve": "3.1.0"
79
79
  },
80
+ "overrides": {
81
+ "@ant-design/charts": {
82
+ "@ant-design/icons": "$@ant-design/icons",
83
+ "antd": "$antd"
84
+ },
85
+ "react-fast-marquee": {
86
+ "react": "$react",
87
+ "react-dom": "$react-dom"
88
+ },
89
+ "react-highlight-words": {
90
+ "react": "$react",
91
+ "react-dom": "$react-dom"
92
+ },
93
+ "react-text-loop": {
94
+ "react": "$react",
95
+ "react-dom": "$react-dom"
96
+ }
97
+ },
80
98
  "babel": {
81
99
  "presets": [
82
100
  "@babel/preset-react",
@@ -49,13 +49,15 @@ Those elements have the following types:
49
49
  - `title` (a list of or a singular dash component, string or number; required): 必填,当前字段标题
50
50
  - `dataIndex` (String; required): 必填,当前字段唯一识别id
51
51
  - `group` (String | Array of Strings; optional): 当前字段所属分组信息,用于渲染多级表头
52
- - `renderOptions` (optional): 配置字段[再渲染模式](/AntdTable-rerender)相关参数. renderOptions has the following type: lists containing elements 'renderType', 'renderLinkText', 'renderButtonSplit', 'renderButtonPopConfirmProps', 'miniChartColor', 'tooltipCustomContent', 'progressOneHundredPercentColor', 'progressShowPercent', 'progressPercentPrecision', 'progressPercentPosition', 'progressStrokeLinecap', 'progressSize', 'progressColor', 'ringProgressFontSize', 'dropdownProps'.
52
+ - `renderOptions` (optional): 配置字段[再渲染模式](/AntdTable-rerender)相关参数. renderOptions has the following type: lists containing elements 'renderType', 'renderLinkText', 'likeDccLink', 'renderButtonSplit', 'renderButtonPopConfirmProps', 'miniChartColor', 'tooltipCustomContent', 'progressOneHundredPercentColor', 'progressShowPercent', 'progressPercentPrecision', 'progressPercentPosition', 'progressStrokeLinecap', 'progressSize', 'progressColor', 'ringProgressFontSize', 'dropdownProps'.
53
53
  Those elements have the following types:
54
54
  - `renderType` (a value equal to: 'link', 'ellipsis', 'copyable', 'ellipsis-copyable', 'tags', 'status-badge', 'image', 'custom-format', 'corner-mark', 'row-merge', 'dropdown', 'dropdown-links', 'image-avatar', 'mini-line', 'mini-bar', 'mini-progress', 'mini-ring-progress', 'mini-area', 'button', 'checkbox', 'switch', 'select'; optional): 再渲染类型,可选项有`'link'`、`'ellipsis'`、`'copyable'`、`'ellipsis-copyable'`、`'tags'`、`'status-badge'`、`'image'`
55
55
  、`'custom-format'`、`'corner-mark'`、`'row-merge'`、`'dropdown'`、`'dropdown-links'`、`'image-avatar'`
56
56
  、`'mini-line'`、`'mini-bar'`、`'mini-progress'`、`'mini-ring-progress'`、`'mini-area'`
57
57
  、`'button'`、`'checkbox'`、`'switch'`、`'select'`
58
58
  - `renderLinkText` (String; optional): 当`renderType='link'`时,统一设置渲染链接文本内容
59
+ - `likeDccLink` (Bool; optional): 当`renderType`为`'link'`、`'button'`时,统一设置链接跳转行为是否采用`dcc.Link`模式
60
+ 默认值:`false`
59
61
  - `renderButtonSplit` (Bool; optional): 当`renderType='button'`时,控制多个按钮之间是否添加分割线
60
62
  - `renderButtonPopConfirmProps` (optional): 当`renderType='button'`时,配置气泡确认框相关参数. renderButtonPopConfirmProps has the following type: lists containing elements 'title', 'okText', 'cancelText'.
61
63
  Those elements have the following types:
@@ -219,6 +219,11 @@ AntdTable.propTypes = {
219
219
  * 当`renderType='link'`时,统一设置渲染链接文本内容
220
220
  */
221
221
  renderLinkText: PropTypes.string,
222
+ /**
223
+ * 当`renderType`为`'link'`、`'button'`时,统一设置链接跳转行为是否采用`dcc.Link`模式
224
+ * 默认值:`false`
225
+ */
226
+ likeDccLink: PropTypes.bool,
222
227
  /**
223
228
  * 当`renderType='button'`时,控制多个按钮之间是否添加分割线
224
229
  */
@@ -1,5 +1,5 @@
1
1
  // react核心
2
- import React, { Component, useEffect, useMemo } from 'react';
2
+ import React, { useEffect, useMemo } from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
  // antd核心
5
5
  import { Menu, Button } from 'antd';
@@ -11,33 +11,14 @@ import {
11
11
  // 辅助库
12
12
  import { get, has, isArray, isUndefined, isNull, isString, cloneDeep } from 'lodash';
13
13
  import { pickBy } from 'ramda';
14
- import isAbsoluteUrl from 'is-absolute-url';
15
14
  import { useLoading } from '../utils';
16
15
  // 自定义hooks
17
16
  import useCss from '../../hooks/useCss';
17
+ // 内部组件
18
+ import { UtilsLink } from '../../internal_components/UtilsLink.react';
18
19
 
19
20
  const { SubMenu, Item, ItemGroup, Divider } = Menu;
20
21
 
21
- // 自定义UtilsLink
22
- function CustomEvent(event, params) {
23
- params = params || {
24
- bubbles: false,
25
- cancelable: false,
26
- detail: undefined
27
- };
28
- const evt = document.createEvent('CustomEvent');
29
- evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
30
- return evt;
31
- }
32
- CustomEvent.prototype = window.Event.prototype;
33
-
34
- function isExternalLink(external_link, href) {
35
- if (isUndefined(external_link) || isNull(external_link)) {
36
- return isAbsoluteUrl(href);
37
- }
38
- return external_link;
39
- }
40
-
41
22
  function findByKey(array, key) {
42
23
  for (let item of array) {
43
24
  if (get(item, 'props.key') === key) {
@@ -87,63 +68,6 @@ const getLevelKeys = (items1) => {
87
68
  return key;
88
69
  };
89
70
 
90
- class UtilsLink extends Component {
91
-
92
- constructor(props) {
93
- super(props);
94
- this.updateLocation = this.updateLocation.bind(this);
95
- }
96
-
97
- updateLocation(e) {
98
- const hasModifiers = e.metaKey || e.shiftKey || e.altKey || e.ctrlKey;
99
- if (hasModifiers) {
100
- return;
101
- }
102
- if (this.props.disabled) {
103
- e.preventDefault();
104
- return;
105
- }
106
- if (this.props.preOnClick) {
107
- this.props.preOnClick();
108
- }
109
- const { external_link, href } = this.props;
110
- if (href && !isExternalLink(external_link, href)) {
111
- // prevent anchor from updating location
112
- e.preventDefault();
113
- const { href } = this.props;
114
- window.history.pushState({}, '', href);
115
- window.dispatchEvent(new CustomEvent('_dashprivate_pushstate'));
116
- // scroll back to top
117
- window.scrollTo(0, 0);
118
- }
119
- }
120
-
121
- render() {
122
- const {
123
- children,
124
- external_link,
125
- preOnClick,
126
- target,
127
- href,
128
- download,
129
- ...otherProps
130
- } = this.props;
131
- const linkIsExternal = href && isExternalLink(external_link, href);
132
-
133
- return (
134
- <a
135
- href={href}
136
- target={linkIsExternal ? target : null}
137
- download={download && linkIsExternal ? download : null}
138
- {...otherProps}
139
- onClick={e => this.updateLocation(e)}
140
- >
141
- {children}
142
- </a>
143
- );
144
- }
145
- }
146
-
147
71
  // 字符串 -> 组件
148
72
  const str2Jsx = new Map([
149
73
  ['SubMenu', SubMenu],
@@ -53,6 +53,8 @@ import useStickyOffset from '../hooks/useStickyOffset';
53
53
  import PropsContext from '../contexts/PropsContext';
54
54
  // 参数类型
55
55
  import { propTypes, defaultProps } from '../components/dataDisplay/AntdTable.react';
56
+ // 内部组件
57
+ import { UtilsLink } from '../internal_components/UtilsLink.react';
56
58
 
57
59
  const { Text } = Typography;
58
60
 
@@ -1005,12 +1007,22 @@ const AntdTable = (props) => {
1005
1007
  return null;
1006
1008
  }
1007
1009
  return (
1008
- <a href={content.disabled ? undefined : content.href}
1009
- target={content.target ? content.target : '_blank'}
1010
- disabled={content.disabled}>
1011
- {content.content ? content.content : columns[i]['renderOptions']['renderLinkText']}
1012
- </a>
1013
- )
1010
+ columns[i]['renderOptions']['likeDccLink'] ?
1011
+ (
1012
+ <UtilsLink href={content.disabled ? undefined : content.href}
1013
+ target={content.target ? content.target : '_blank'}
1014
+ disabled={content.disabled}>
1015
+ {content.content ? content.content : columns[i]['renderOptions']['renderLinkText']}
1016
+ </UtilsLink>
1017
+ ) :
1018
+ (
1019
+ <a href={content.disabled ? undefined : content.href}
1020
+ target={content.target ? content.target : '_blank'}
1021
+ disabled={content.disabled}>
1022
+ {content.content ? content.content : columns[i]['renderOptions']['renderLinkText']}
1023
+ </a>
1024
+ )
1025
+ );
1014
1026
  }
1015
1027
  } else {
1016
1028
  columns[i]['render'] = content => {
@@ -1018,12 +1030,22 @@ const AntdTable = (props) => {
1018
1030
  return null;
1019
1031
  }
1020
1032
  return (
1021
- <a href={content.disabled ? undefined : content.href}
1022
- target={content.target ? content.target : '_blank'}
1023
- disabled={content.disabled}>
1024
- {content.content ? content.content : ' '}
1025
- </a>
1026
- )
1033
+ columns[i]['renderOptions']['likeDccLink'] ?
1034
+ (
1035
+ <UtilsLink href={content.disabled ? undefined : content.href}
1036
+ target={content.target ? content.target : '_blank'}
1037
+ disabled={content.disabled}>
1038
+ {content.content ? content.content : ' '}
1039
+ </UtilsLink>
1040
+ ) :
1041
+ (
1042
+ <a href={content.disabled ? undefined : content.href}
1043
+ target={content.target ? content.target : '_blank'}
1044
+ disabled={content.disabled}>
1045
+ {content.content ? content.content : ' '}
1046
+ </a>
1047
+ )
1048
+ );
1027
1049
  }
1028
1050
  }
1029
1051
  }
@@ -1475,7 +1497,9 @@ const AntdTable = (props) => {
1475
1497
  key={idx}
1476
1498
  onClick={(e) => {
1477
1499
  // 阻止事件冒泡
1478
- e.stopPropagation();
1500
+ if ( !columns[i]['renderOptions']['likeDccLink'] ) {
1501
+ e.stopPropagation();
1502
+ }
1479
1503
  setProps({
1480
1504
  // 忽略组件型字段键值对
1481
1505
  recentlyButtonClickedRow: omitBy(record, value => value?.$$typeof),
@@ -1491,7 +1515,7 @@ const AntdTable = (props) => {
1491
1515
  variant={content_.variant}
1492
1516
  danger={content_.danger}
1493
1517
  disabled={content_.disabled}
1494
- href={content_.href}
1518
+ href={columns[i]['renderOptions']['likeDccLink'] ? undefined : content_.href}
1495
1519
  target={content_.target}
1496
1520
  style={content_.style}
1497
1521
  icon={
@@ -1518,11 +1542,23 @@ const AntdTable = (props) => {
1518
1542
  content_.tooltip ?
1519
1543
  (
1520
1544
  <Tooltip title={content_.tooltip?.title} placement={content_.tooltip?.placement}>
1521
- {buttonElement}
1545
+ {
1546
+ (
1547
+ columns[i]['renderOptions']['likeDccLink'] ?
1548
+ (
1549
+ <UtilsLink key={idx} href={content_.href}>{buttonElement}</UtilsLink>
1550
+ ) :
1551
+ buttonElement
1552
+ )
1553
+ }
1522
1554
  </Tooltip>
1523
1555
  ) :
1524
1556
  (
1525
- buttonElement
1557
+ columns[i]['renderOptions']['likeDccLink'] ?
1558
+ (
1559
+ <UtilsLink key={idx} href={content_.href}>{buttonElement}</UtilsLink>
1560
+ ) :
1561
+ buttonElement
1526
1562
  )
1527
1563
  );
1528
1564
  }
@@ -0,0 +1,82 @@
1
+ import { Component } from "react";
2
+ import isAbsoluteUrl from 'is-absolute-url';
3
+ import { isUndefined, isNull } from 'lodash';
4
+
5
+ function CustomEvent(event, params) {
6
+ params = params || {
7
+ bubbles: false,
8
+ cancelable: false,
9
+ detail: undefined,
10
+ };
11
+ const evt = document.createEvent("CustomEvent");
12
+ evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
13
+ return evt;
14
+ }
15
+ CustomEvent.prototype = window.Event.prototype;
16
+
17
+ function isExternalLink(external_link, href) {
18
+ if (isUndefined(external_link) || isNull(external_link)) {
19
+ return isAbsoluteUrl(href);
20
+ }
21
+ return external_link;
22
+ }
23
+
24
+ class UtilsLink extends Component {
25
+ constructor(props) {
26
+ super(props);
27
+ this.updateLocation = this.updateLocation.bind(this);
28
+ }
29
+
30
+ updateLocation(e) {
31
+ const hasModifiers = e.metaKey || e.shiftKey || e.altKey || e.ctrlKey;
32
+ if (hasModifiers) {
33
+ return;
34
+ }
35
+ if (this.props.disabled) {
36
+ e.preventDefault();
37
+ return;
38
+ }
39
+ if (this.props.preOnClick) {
40
+ this.props.preOnClick();
41
+ }
42
+ const { external_link, href } = this.props;
43
+ if (href && !isExternalLink(external_link, href)) {
44
+ // prevent anchor from updating location
45
+ e.preventDefault();
46
+ const { href } = this.props;
47
+ window.history.pushState({}, "", href);
48
+ window.dispatchEvent(new CustomEvent("_dashprivate_pushstate"));
49
+ // scroll back to top
50
+ window.scrollTo(0, 0);
51
+ }
52
+ }
53
+
54
+ render() {
55
+ const {
56
+ children,
57
+ external_link,
58
+ preOnClick,
59
+ target,
60
+ href,
61
+ download,
62
+ disabled,
63
+ ...otherProps
64
+ } = this.props;
65
+ const linkIsExternal = href && isExternalLink(external_link, href);
66
+
67
+ return (
68
+ <a
69
+ href={href}
70
+ target={linkIsExternal ? target : null}
71
+ download={download && linkIsExternal ? download : null}
72
+ disabled={disabled}
73
+ {...otherProps}
74
+ onClick={(e) => this.updateLocation(e)}
75
+ >
76
+ {children}
77
+ </a>
78
+ );
79
+ }
80
+ }
81
+
82
+ export { UtilsLink };
@@ -0,0 +1,125 @@
1
+ if True:
2
+ import sys
3
+
4
+ sys.path.append('../../../')
5
+ import json
6
+ import dash
7
+ from dash import html
8
+ import feffery_antd_components as fac
9
+ from dash.dependencies import Input, Output, State
10
+
11
+ app = dash.Dash(__name__)
12
+
13
+ app.layout = html.Div(
14
+ [
15
+ fac.AntdSwitch(),
16
+ fac.AntdTable(
17
+ id='table-rerender-button-demo',
18
+ columns=[
19
+ {
20
+ 'title': 'button示例1',
21
+ 'dataIndex': 'button示例1',
22
+ 'renderOptions': {
23
+ 'renderType': 'button',
24
+ 'likeDccLink': True,
25
+ },
26
+ },
27
+ {
28
+ 'title': 'button示例2',
29
+ 'dataIndex': 'button示例2',
30
+ 'renderOptions': {
31
+ 'renderType': 'button'
32
+ },
33
+ },
34
+ {
35
+ 'title': 'button示例3',
36
+ 'dataIndex': 'button示例3',
37
+ 'renderOptions': {
38
+ 'renderType': 'button',
39
+ 'renderButtonPopConfirmProps': {
40
+ 'title': '确认执行?',
41
+ 'okText': '确认',
42
+ 'cancelText': '取消',
43
+ },
44
+ },
45
+ },
46
+ ],
47
+ data=[
48
+ {
49
+ 'button示例1': {
50
+ 'content': f'按钮1-{i}',
51
+ 'type': 'link',
52
+ 'href': f'/item{i}',
53
+ 'custom': 'balabalabalabala',
54
+ },
55
+ 'button示例2': [
56
+ {
57
+ 'content': f'按钮2-{i}-{j}',
58
+ 'type': 'primary',
59
+ 'custom': 'balabalabalabala',
60
+ }
61
+ for j in range(1, 3)
62
+ ],
63
+ 'button示例3': [
64
+ {
65
+ 'content': f'按钮3-{i}-{j}',
66
+ 'type': 'dashed',
67
+ 'danger': True,
68
+ 'custom': 'balabalabalabala',
69
+ }
70
+ for j in range(1, 3)
71
+ ],
72
+ }
73
+ for i in range(1, 4)
74
+ ],
75
+ bordered=True,
76
+ ),
77
+ html.Pre(id='table-rerender-button-demo-output'),
78
+ ],
79
+ style={'padding': 100},
80
+ )
81
+
82
+
83
+ @app.callback(
84
+ Output('table-rerender-button-demo-output', 'children'),
85
+ Input('table-rerender-button-demo', 'nClicksButton'),
86
+ [
87
+ State(
88
+ 'table-rerender-button-demo', 'clickedContent'
89
+ ),
90
+ State(
91
+ 'table-rerender-button-demo', 'clickedCustom'
92
+ ),
93
+ State(
94
+ 'table-rerender-button-demo',
95
+ 'recentlyButtonClickedDataIndex',
96
+ ),
97
+ State(
98
+ 'table-rerender-button-demo',
99
+ 'recentlyButtonClickedRow',
100
+ ),
101
+ ],
102
+ prevent_initial_call=True,
103
+ )
104
+ def table_rerender_button_demo(
105
+ nClicksButton,
106
+ clickedContent,
107
+ clickedCustom,
108
+ recentlyButtonClickedDataIndex,
109
+ recentlyButtonClickedRow,
110
+ ):
111
+ return json.dumps(
112
+ dict(
113
+ nClicksButton=nClicksButton,
114
+ clickedContent=clickedContent,
115
+ clickedCustom=clickedCustom,
116
+ recentlyButtonClickedDataIndex=recentlyButtonClickedDataIndex,
117
+ recentlyButtonClickedRow=recentlyButtonClickedRow,
118
+ ),
119
+ indent=4,
120
+ ensure_ascii=False,
121
+ )
122
+
123
+
124
+ if __name__ == '__main__':
125
+ app.run(debug=True)
@@ -0,0 +1,49 @@
1
+ if True:
2
+ import sys
3
+
4
+ sys.path.append('../../../')
5
+ import dash
6
+ from dash import html
7
+ import feffery_antd_components as fac
8
+
9
+ app = dash.Dash(__name__)
10
+
11
+ app.layout = html.Div(
12
+ [
13
+ fac.AntdSwitch(),
14
+ fac.AntdTable(
15
+ columns=[
16
+ {
17
+ 'title': 'link示例',
18
+ 'dataIndex': 'link示例',
19
+ 'renderOptions': {
20
+ 'renderType': 'link',
21
+ 'likeDccLink': True,
22
+ },
23
+ },
24
+ ],
25
+ data=[
26
+ {
27
+ 'link示例': {
28
+ 'content': f'{content}仓库',
29
+ 'href': '/' + content,
30
+ },
31
+ }
32
+ for content in [
33
+ 'fac',
34
+ 'fuc',
35
+ 'fact',
36
+ 'fmc',
37
+ 'flc',
38
+ ]
39
+ ],
40
+ bordered=True,
41
+ style={'width': 400},
42
+ ),
43
+ ],
44
+ style={'padding': 100},
45
+ )
46
+
47
+
48
+ if __name__ == '__main__':
49
+ app.run(debug=True)