@alifd/chat 0.2.0-beta.1 → 0.2.0-beta.2

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.
Files changed (55) hide show
  1. package/es/HTMLRenderer/index.d.ts +4 -0
  2. package/es/HTMLRenderer/index.js +138 -0
  3. package/es/HTMLRenderer/index.less +194 -0
  4. package/es/HTMLRenderer/main.scss +233 -0
  5. package/es/HTMLRenderer/style.d.ts +1 -0
  6. package/es/HTMLRenderer/style.js +1 -0
  7. package/es/HTMLRenderer/types.d.ts +46 -0
  8. package/es/HTMLRenderer/types.js +1 -0
  9. package/es/ImagePreview/index.d.ts +13 -0
  10. package/es/ImagePreview/index.js +72 -0
  11. package/es/ImagePreview/main.scss +15 -0
  12. package/es/ImagePreview/style.d.ts +1 -0
  13. package/es/ImagePreview/style.js +1 -0
  14. package/es/ImagePreview/types.d.ts +31 -0
  15. package/es/ImagePreview/types.js +1 -0
  16. package/es/feedback/types.d.ts +6 -11
  17. package/es/index.d.ts +3 -0
  18. package/es/index.js +4 -1
  19. package/es/markdown/index.d.ts +6 -0
  20. package/es/markdown/index.js +138 -0
  21. package/es/markdown/main.scss +153 -0
  22. package/es/markdown/style.d.ts +3 -0
  23. package/es/markdown/style.js +3 -0
  24. package/es/markdown/types.d.ts +21 -0
  25. package/es/markdown/types.js +1 -0
  26. package/es/utils/func.d.ts +1 -0
  27. package/es/utils/func.js +9 -0
  28. package/lib/HTMLRenderer/index.d.ts +4 -0
  29. package/lib/HTMLRenderer/index.js +141 -0
  30. package/lib/HTMLRenderer/index.less +194 -0
  31. package/lib/HTMLRenderer/main.scss +233 -0
  32. package/lib/HTMLRenderer/style.d.ts +1 -0
  33. package/lib/HTMLRenderer/style.js +3 -0
  34. package/lib/HTMLRenderer/types.d.ts +46 -0
  35. package/lib/HTMLRenderer/types.js +2 -0
  36. package/lib/ImagePreview/index.d.ts +13 -0
  37. package/lib/ImagePreview/index.js +75 -0
  38. package/lib/ImagePreview/main.scss +15 -0
  39. package/lib/ImagePreview/style.d.ts +1 -0
  40. package/lib/ImagePreview/style.js +3 -0
  41. package/lib/ImagePreview/types.d.ts +31 -0
  42. package/lib/ImagePreview/types.js +2 -0
  43. package/lib/feedback/types.d.ts +6 -11
  44. package/lib/index.d.ts +3 -0
  45. package/lib/index.js +8 -2
  46. package/lib/markdown/index.d.ts +6 -0
  47. package/lib/markdown/index.js +141 -0
  48. package/lib/markdown/main.scss +153 -0
  49. package/lib/markdown/style.d.ts +3 -0
  50. package/lib/markdown/style.js +5 -0
  51. package/lib/markdown/types.d.ts +21 -0
  52. package/lib/markdown/types.js +2 -0
  53. package/lib/utils/func.d.ts +1 -0
  54. package/lib/utils/func.js +10 -0
  55. package/package.json +49 -1
@@ -0,0 +1,4 @@
1
+ import { HTMLRendererProps } from './types';
2
+ export * from './types';
3
+ declare const _default: import("@alifd/next/types/config-provider/types").ConfiguredComponentClass<HTMLRendererProps & import("@alifd/next/types/config-provider/types").ComponentCommonProps, unknown, {}>;
4
+ export default _default;
@@ -0,0 +1,138 @@
1
+ /**
2
+ * @component HTML 渲染器
3
+ * @en HTML Renderer
4
+ * @type 通用 - General
5
+ * @remarks HTML 渲染组件用于解析和渲染 HTML 字符串,同时提供图片预览、链接处理和文本复制等功能。 - HTML renderer component used to parse and render HTML strings, with additional features such as image zoom, link handling, text copying and so on.
6
+ * @when 需要解析和渲染 HTML 字符串时使用。 - Use when you need to parse and render HTML strings.
7
+ */
8
+ import React, { memo, useMemo } from 'react';
9
+ import classnames from 'classnames';
10
+ import sanitizeHtml from 'sanitize-html';
11
+ import parse, { domToReact, Element } from 'html-react-parser';
12
+ import { PhotoProvider } from 'react-photo-view';
13
+ import qs from 'query-string';
14
+ import ImagePreview from '../ImagePreview';
15
+ import { ConfigProvider } from '@alifd/next';
16
+ import { assignSubComponent } from '../utils';
17
+ const sanitizeHtmlOptions = {
18
+ allowedTags: sanitizeHtml.defaults.allowedTags.concat([
19
+ 'acronym', 'audio', 'big', 'center', 'del', 'dir', 'font',
20
+ 'img', 'ins', 'source', 'strike', 'track', 'tt', 'video',
21
+ ]),
22
+ allowedAttributes: {
23
+ '*': ['data-*', 'title', 'align', 'bgcolor', 'class', 'style'],
24
+ a: ['href', 'download'],
25
+ audio: ['controls', 'crossorigin', 'loop', 'muted', 'preload', 'src'],
26
+ br: ['clear'],
27
+ caption: ['align'],
28
+ col: ['span'],
29
+ colgroup: ['span'],
30
+ font: ['color', 'face', 'size'],
31
+ hr: ['color', 'noshade', 'size'],
32
+ img: ['alt', 'src', 'crossorigin', 'decoding', 'sizes', 'srcset', 'align', 'width', 'height'],
33
+ li: ['value', 'type'],
34
+ ol: ['reversed', 'start', 'type'],
35
+ source: ['sizes', 'src', 'srcset', 'type', 'media'],
36
+ table: ['border', 'cellpadding', 'cellspacing', 'frame', 'rules', 'summary'],
37
+ td: ['headers', 'colspan', 'rowspan'],
38
+ th: ['headers', 'colspan', 'rowspan'],
39
+ track: ['default', 'kind', 'label', 'src', 'srclang'],
40
+ ul: ['type'],
41
+ video: ['controls', 'crossorigin', 'loop', 'muted', 'preload', 'src', 'poster', 'width', 'height'],
42
+ },
43
+ enforceHtmlBoundary: false,
44
+ disallowedTagsMode: 'discard',
45
+ allowedSchemes: ['http', 'https', 'ftp', 'mailto', 'tel', 'message', 'copy', 'dingtalk', 'dtmd'],
46
+ allowedSchemesAppliedToAttributes: ['href', 'src', 'cite'],
47
+ allowProtocolRelative: false,
48
+ };
49
+ const HTMLRenderer = memo(function HTMLRenderer({ className, children, imagePreview, loose, handleOpenLink, sendTextMessage, copyText, i18n }) {
50
+ // 处理钉钉特定链接
51
+ function handleDingtalkUrl(href) {
52
+ return () => {
53
+ const { query } = qs.parseUrl(href);
54
+ const { content, url, _assistant_adaptation, context } = query;
55
+ if (_assistant_adaptation === 'false') {
56
+ delete query._assistant_adaptation;
57
+ const newUrl = qs.stringifyUrl({ url: href, query }, { sort: false });
58
+ handleOpenLink === null || handleOpenLink === void 0 ? void 0 : handleOpenLink(newUrl);
59
+ return;
60
+ }
61
+ let contextObj;
62
+ try {
63
+ contextObj = JSON.parse(context || '');
64
+ }
65
+ catch (e) {
66
+ contextObj = {};
67
+ }
68
+ if (contextObj.allowToDingtalk && contextObj.allowToDingtalk === true) {
69
+ handleOpenLink === null || handleOpenLink === void 0 ? void 0 : handleOpenLink(href);
70
+ }
71
+ else if (content) {
72
+ sendTextMessage === null || sendTextMessage === void 0 ? void 0 : sendTextMessage(`${content}`);
73
+ }
74
+ else if (url) {
75
+ handleOpenLink === null || handleOpenLink === void 0 ? void 0 : handleOpenLink(url === null || url === void 0 ? void 0 : url.toString());
76
+ }
77
+ else {
78
+ handleOpenLink === null || handleOpenLink === void 0 ? void 0 : handleOpenLink(href);
79
+ }
80
+ };
81
+ }
82
+ const parserOptions = {
83
+ replace: domNode => {
84
+ if (domNode instanceof Element && domNode.attribs) {
85
+ const { name } = domNode;
86
+ if (name === 'a') {
87
+ const element = (domToReact([domNode]));
88
+ const { props } = element;
89
+ if (props.href && props.href.startsWith('message://')) {
90
+ const msgValue = decodeURIComponent(props.href.slice(10));
91
+ return React.cloneElement(element, {
92
+ onClick: () => sendTextMessage === null || sendTextMessage === void 0 ? void 0 : sendTextMessage(msgValue),
93
+ href: undefined
94
+ });
95
+ }
96
+ if (props.href && props.href.startsWith('copy://')) {
97
+ const copyValue = decodeURIComponent(props.href.slice(7));
98
+ return React.cloneElement(element, {
99
+ onClick: copyText === null || copyText === void 0 ? void 0 : copyText(copyValue, i18n),
100
+ href: undefined
101
+ });
102
+ }
103
+ if (props.href && /^dtmd:\/\/dingtalkclient|^dingtalk:\/\/dingtalkclient\/action\/jumprobot|^(https?:)?\/\/qr.dingtalk.com\/action\/jumprobot/.test(props.href)) {
104
+ return React.cloneElement(element, {
105
+ onClick: handleDingtalkUrl(props.href),
106
+ href: undefined
107
+ });
108
+ }
109
+ return React.cloneElement(element, {
110
+ target: '_blank',
111
+ });
112
+ }
113
+ if (name === 'img') {
114
+ const element = (domToReact([domNode]));
115
+ if (imagePreview) {
116
+ return React.createElement(ImagePreview, { className: "image", src: element.props.src }, element);
117
+ }
118
+ else {
119
+ return element;
120
+ }
121
+ }
122
+ }
123
+ }
124
+ };
125
+ const element = useMemo(() => {
126
+ return parse(sanitizeHtml(children || '', sanitizeHtmlOptions), parserOptions);
127
+ }, [children]);
128
+ return (React.createElement("div", { className: classnames('box', className, {
129
+ 'loose': loose,
130
+ }) }, imagePreview ?
131
+ React.createElement(PhotoProvider, null, element)
132
+ : element));
133
+ });
134
+ const HTMLRendererWithSub = assignSubComponent(HTMLRenderer, {
135
+ displayName: 'HTMLRenderer',
136
+ });
137
+ export * from './types';
138
+ export default ConfigProvider.config(HTMLRendererWithSub);
@@ -0,0 +1,194 @@
1
+ @import '../../var.less';
2
+
3
+ .box {
4
+ font-size: 14px;
5
+ // color: hsla(230, 10%, 11%, 0.9);
6
+ word-break: break-word;
7
+ font-family: inherit;
8
+ .loose& {
9
+ font-size: 16px;
10
+ line-height: 1.85;
11
+ }
12
+ @media print {
13
+ color: #000 !important;
14
+ font-family: 'Times New Roman', Times, serif;
15
+ }
16
+ body:global(.dark) & {
17
+ filter: invert(1) hue-rotate(180deg);
18
+ }
19
+ img, video, iframe {
20
+ body:global(.dark) & {
21
+ filter: hue-rotate(180deg) invert(1);
22
+ }
23
+ }
24
+ img {
25
+ body:global(.dark) & {
26
+ background: #fff;
27
+ }
28
+ body:global(.dark.dim) & {
29
+ filter: hue-rotate(180deg) brightness(.75) invert(1);
30
+ }
31
+ }
32
+ body:global(.dark) & :global(.symbolic) > img {
33
+ filter: none;
34
+ background: none;
35
+ }
36
+ h1, h2, h3, h4, h5, h6, p, blockquote, table, .syntax-highlighter {
37
+ margin: 0;
38
+ .loose& {
39
+ margin: 20px 0;
40
+ }
41
+ }
42
+ h1, h2, h3, h4, h5, h6 {
43
+ font-weight: bold;
44
+ }
45
+ h1 {
46
+ font-size: 18px;
47
+ line-height: 1.8;
48
+ .loose& {
49
+ font-size: 28px;
50
+ }
51
+ }
52
+ h2 {
53
+ font-size: 16px;
54
+ line-height: 1.8;
55
+ .loose& {
56
+ font-size: 24px;
57
+ }
58
+ }
59
+ h3, h4, h5, h6 {
60
+ font-size: 14px;
61
+ line-height: 1.9;
62
+ }
63
+ h3 {
64
+ .loose& {
65
+ font-size: 18px;
66
+ }
67
+ }
68
+ h4, h5, h6 {
69
+ .loose& {
70
+ font-size: 16px;
71
+ }
72
+ }
73
+ img, video, .image {
74
+ max-width: 100%!important;
75
+ height: auto!important;
76
+ &:only-child {
77
+ display: block;
78
+ margin: 10px auto;
79
+ }
80
+ }
81
+ .image:only-child {
82
+ width: fit-content;
83
+ }
84
+ .image img {
85
+ margin: 0;
86
+ }
87
+ code {
88
+ margin: 0 .15em;
89
+ padding: .12em .25em;
90
+ border-radius: 3px;
91
+ font-size: 86%;
92
+ background: rgba(27,31,35,.05);
93
+ }
94
+ pre {
95
+ font-size: 14px;
96
+ line-height: 1.6;
97
+ border-radius: 2px;
98
+ border: 6px solid transparent;
99
+ overflow: auto;
100
+ margin: 0;
101
+ code {
102
+ font-size: 14px;
103
+ padding: 0;
104
+ margin: 0;
105
+ border: none;
106
+ font-size: inherit;
107
+ background: none;
108
+ border-radius: 0;
109
+ }
110
+ }
111
+ table, td, th {
112
+ border: 1px solid #caccce;
113
+ body:global(.dark) & {
114
+ border-color: #babcbd;
115
+ // border-color: #c9cace;
116
+ }
117
+ border-collapse: collapse;
118
+ border-spacing: 0;
119
+ }
120
+ table {
121
+ line-height: 1.6;
122
+ margin: 10px auto;
123
+ border-spacing: none;
124
+ border-collapse: collapse;
125
+ empty-cells: show;
126
+ font-size: 14px;
127
+ .loose& p {
128
+ margin: 0;
129
+ }
130
+ }
131
+ td, th {
132
+ border: 1px solid #e3e3e3;
133
+ padding: 10px 12px;
134
+ line-height: 1.3;
135
+ p {
136
+ margin: 0;
137
+ }
138
+ }
139
+ th {
140
+ background: hsla(230, 90%, 11%,.03);
141
+ }
142
+ a, a:visited {
143
+ color: #0080FF;
144
+ text-decoration: none;
145
+ &:hover {
146
+ text-decoration: underline;
147
+ }
148
+ }
149
+ ul, ol {
150
+ list-style: revert;
151
+ padding-left: 16px;
152
+ .loose& {
153
+ padding-left: 30px;
154
+ }
155
+ }
156
+ li {
157
+ list-style: revert;
158
+ }
159
+ blockquote {
160
+ opacity: 1;
161
+ border: none;
162
+ padding: 0;
163
+ margin-left: 20px;
164
+ opacity: 0.6;
165
+ font-style: italic;
166
+ position: relative;
167
+ margin-top: 6px;
168
+ margin-bottom: 6px;
169
+ .loose& {
170
+ margin-top: 20px;
171
+ margin-bottom: 20px;
172
+ }
173
+ &::before {
174
+ content: '|';
175
+ font-size: 0;
176
+ color: transparent;
177
+ display: inline-block;
178
+ width: 4px;
179
+ border-radius: 1px;
180
+ position: absolute;
181
+ margin-left: -16px;
182
+ top: 0;
183
+ bottom: 0;
184
+ background: hsla(230, 90%, 11%,.2);
185
+ }
186
+ }
187
+ hr {
188
+ height: 0;
189
+ border: none;
190
+ height: 1px;
191
+ background: hsla(230, 90%, 11%,.1);
192
+ margin: 10px 0;
193
+ }
194
+ }
@@ -0,0 +1,233 @@
1
+ .box {
2
+ font-size: 14px;
3
+ // color: hsla(230, 10%, 11%, 0.9);
4
+ word-break: break-word;
5
+ font-family: inherit;
6
+
7
+ &.loose {
8
+ font-size: 16px;
9
+ line-height: 1.85;
10
+ }
11
+
12
+ @media print {
13
+ color: #000 !important;
14
+ font-family: 'Times New Roman', Times, serif;
15
+ }
16
+
17
+ body.global-dark & {
18
+ filter: invert(1) hue-rotate(180deg);
19
+ }
20
+
21
+ img, video, iframe {
22
+ body.global-dark & {
23
+ filter: hue-rotate(180deg) invert(1);
24
+ }
25
+ }
26
+
27
+ img {
28
+ body.global-dark & {
29
+ background: #fff;
30
+ }
31
+ body.global-dark-dim & {
32
+ filter: hue-rotate(180deg) brightness(.75) invert(1);
33
+ }
34
+ }
35
+
36
+ body.global-dark & .symbolic > img {
37
+ filter: none;
38
+ background: none;
39
+ }
40
+
41
+ h1, h2, h3, h4, h5, h6, p, blockquote, table, .syntax-highlighter {
42
+ margin: 0;
43
+
44
+ &.loose {
45
+ margin: 20px 0;
46
+ }
47
+ }
48
+
49
+ h1, h2, h3, h4, h5, h6 {
50
+ font-weight: bold;
51
+ }
52
+
53
+ h1 {
54
+ font-size: 18px;
55
+ line-height: 1.8;
56
+
57
+ &.loose {
58
+ font-size: 28px;
59
+ }
60
+ }
61
+
62
+ h2 {
63
+ font-size: 16px;
64
+ line-height: 1.8;
65
+
66
+ &.loose {
67
+ font-size: 24px;
68
+ }
69
+ }
70
+
71
+ h3, h4, h5, h6 {
72
+ font-size: 14px;
73
+ line-height: 1.9;
74
+ }
75
+
76
+ h3 {
77
+ &.loose {
78
+ font-size: 18px;
79
+ }
80
+ }
81
+
82
+ h4, h5, h6 {
83
+ &.loose {
84
+ font-size: 16px;
85
+ }
86
+ }
87
+
88
+ img, video, .image {
89
+ max-width: 100% !important;
90
+ height: auto !important;
91
+
92
+ &:only-child {
93
+ display: block;
94
+ margin: 10px auto;
95
+ }
96
+ }
97
+
98
+ .image:only-child {
99
+ width: fit-content;
100
+ }
101
+
102
+ .image img {
103
+ margin: 0;
104
+ }
105
+
106
+ code {
107
+ margin: 0 .15em;
108
+ padding: .12em .25em;
109
+ border-radius: 3px;
110
+ font-size: 86%;
111
+ background: rgba(27, 31, 35, .05);
112
+ }
113
+
114
+ pre {
115
+ font-size: 14px;
116
+ line-height: 1.6;
117
+ border-radius: 4px;
118
+ border: 6px solid transparent;
119
+ overflow: auto;
120
+ margin: 0 0 8px 0;
121
+
122
+ code {
123
+ font-size: 14px;
124
+ padding: 0;
125
+ margin: 0;
126
+ border: none;
127
+ font-size: inherit;
128
+ background: none;
129
+ border-radius: 0;
130
+ }
131
+ }
132
+
133
+ table, td, th {
134
+ border: 1px solid #caccce;
135
+
136
+ body.global-dark & {
137
+ border-color: #babcbd;
138
+ // border-color: #c9cace;
139
+ }
140
+
141
+ border-collapse: collapse;
142
+ border-spacing: 0;
143
+ }
144
+
145
+ table {
146
+ line-height: 1.6;
147
+ margin: 10px auto;
148
+ border-spacing: none;
149
+ border-collapse: collapse;
150
+ empty-cells: show;
151
+ font-size: 14px;
152
+
153
+ &.loose p {
154
+ margin: 0;
155
+ }
156
+ }
157
+
158
+ td, th {
159
+ border: 1px solid #e3e3e3;
160
+ padding: 10px 12px;
161
+ line-height: 1.3;
162
+
163
+ p {
164
+ margin: 0;
165
+ }
166
+ }
167
+
168
+ th {
169
+ background: hsla(230, 90%, 11%, .03);
170
+ }
171
+
172
+ a, a:visited {
173
+ color: #0080FF;
174
+ text-decoration: none;
175
+
176
+ &:hover {
177
+ text-decoration: underline;
178
+ }
179
+ }
180
+
181
+ ul, ol {
182
+ list-style: revert;
183
+ padding-left: 16px;
184
+ margin: 0;
185
+
186
+ &.loose {
187
+ padding-left: 30px;
188
+ }
189
+ }
190
+
191
+ li {
192
+ list-style: revert;
193
+ }
194
+
195
+ blockquote {
196
+ opacity: 1;
197
+ border: none;
198
+ padding: 0;
199
+ margin-left: 20px;
200
+ opacity: 0.6;
201
+ font-style: italic;
202
+ position: relative;
203
+ margin-top: 6px;
204
+ margin-bottom: 6px;
205
+
206
+ &.loose {
207
+ margin-top: 20px;
208
+ margin-bottom: 20px;
209
+ }
210
+
211
+ &::before {
212
+ content: '|';
213
+ font-size: 0;
214
+ color: transparent;
215
+ display: inline-block;
216
+ width: 4px;
217
+ border-radius: 1px;
218
+ position: absolute;
219
+ margin-left: -16px;
220
+ top: 0;
221
+ bottom: 0;
222
+ background: hsla(230, 90%, 11%, .2);
223
+ }
224
+ }
225
+
226
+ hr {
227
+ height: 0;
228
+ border: none;
229
+ height: 1px;
230
+ background: hsla(230, 90%, 11%, .1);
231
+ margin: 10px 0;
232
+ }
233
+ }
@@ -0,0 +1 @@
1
+ import './main.scss';
@@ -0,0 +1 @@
1
+ import './main.scss';
@@ -0,0 +1,46 @@
1
+ import type React from 'react';
2
+ /**
3
+ * @api HTMLRenderer
4
+ */
5
+ export interface HTMLRendererProps extends React.HTMLAttributes<HTMLElement> {
6
+ /**
7
+ * 自定义类名
8
+ * @en Custom class name
9
+ */
10
+ className?: string;
11
+ /**
12
+ * 是否启用图片预览
13
+ * @en Enable image zoom
14
+ */
15
+ imagePreview?: boolean;
16
+ /**
17
+ * 是否使用松散模式
18
+ * @en Enable loose mode
19
+ */
20
+ loose?: boolean;
21
+ /**
22
+ * 要渲染的 HTML 字符串
23
+ * @en HTML string to render
24
+ */
25
+ children?: string;
26
+ /**
27
+ * 处理打开链接的函数
28
+ * @en Function to handle open link
29
+ */
30
+ handleOpenLink?: (href: string) => void;
31
+ /**
32
+ * 发送文本消息的函数
33
+ * @en Function to send text message
34
+ */
35
+ sendTextMessage?: (message: string) => void;
36
+ /**
37
+ * 复制文本的函数
38
+ * @en Function to copy text
39
+ */
40
+ copyText?: (text: string, i18n?: (key: string) => string) => void;
41
+ /**
42
+ * 国际化函数
43
+ * @en Internationalization function
44
+ */
45
+ i18n?: (key: string) => string;
46
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @component 图片预览
3
+ * @en ImagePreview
4
+ * @type 通用 - General
5
+ * @remarks 图片预览组件用于在钉钉环境中显示和预览图片。 - Image preview component used to display and preview images in DingTalk environment.
6
+ * @when 需要展示图片并提供预览功能时使用。 - Use when you need to display images and provide preview functionality.
7
+
8
+ */
9
+ import React from 'react';
10
+ import { ImagePreviewProps } from './types';
11
+ export * from './types';
12
+ declare const _default: import("@alifd/next/types/config-provider/types").ConfiguredComponentClass<Pick<ImagePreviewProps & React.RefAttributes<HTMLElement>, "key" | keyof ImagePreviewProps> & import("@alifd/next/types/config-provider/types").ComponentCommonProps, HTMLElement, {}>;
13
+ export default _default;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @component 图片预览
3
+ * @en ImagePreview
4
+ * @type 通用 - General
5
+ * @remarks 图片预览组件用于在钉钉环境中显示和预览图片。 - Image preview component used to display and preview images in DingTalk environment.
6
+ * @when 需要展示图片并提供预览功能时使用。 - Use when you need to display images and provide preview functionality.
7
+
8
+ */
9
+ import React, { forwardRef } from 'react';
10
+ import classnames from 'classnames';
11
+ import { PhotoProvider, PhotoView } from 'react-photo-view';
12
+ import { findAncestor } from '../utils';
13
+ import { ConfigProvider } from '@alifd/next';
14
+ import { assignSubComponent } from '../utils';
15
+ import { env as ddEnv, biz as ddBiz } from 'dingtalk-jsapi';
16
+ function handleClick(e, src) {
17
+ if (findAncestor(e.target, t => t.tagName === 'A' && !!t.href)) {
18
+ e.stopPropagation();
19
+ return;
20
+ }
21
+ if (src && ddEnv.version) {
22
+ const a = document.createElement('a');
23
+ a.href = src;
24
+ e.stopPropagation();
25
+ ddBiz.util.previewImage({
26
+ urls: [a.href],
27
+ current: a.href,
28
+ });
29
+ }
30
+ }
31
+ function isInsideLink(e) {
32
+ return !!findAncestor(e.target, (t) => t.tagName === 'A' && !!t.href);
33
+ }
34
+ const ImagePreview = forwardRef(({ className, src, children, width, height }, ref) => {
35
+ let child;
36
+ try {
37
+ child = React.Children.only(children);
38
+ }
39
+ catch (e) { }
40
+ if (child && child.props) {
41
+ const { onClick, onTouchEnd } = child.props;
42
+ child = React.cloneElement(child, {
43
+ onTouchEnd: (e) => {
44
+ if (isInsideLink(e)) {
45
+ e.stopPropagation();
46
+ }
47
+ handleClick(e, src);
48
+ onTouchEnd === null || onTouchEnd === void 0 ? void 0 : onTouchEnd(e);
49
+ },
50
+ onClick: (e) => {
51
+ if (isInsideLink(e)) {
52
+ e.stopPropagation();
53
+ }
54
+ handleClick(e, src);
55
+ onClick === null || onClick === void 0 ? void 0 : onClick(e);
56
+ }
57
+ });
58
+ }
59
+ return (React.createElement(PhotoProvider, null,
60
+ React.createElement(PhotoView, { src: src },
61
+ React.createElement("span", { className: classnames('box', className, {
62
+ 'hasWidth': !!width,
63
+ 'hasHeight': !!height,
64
+ }), style: { width } },
65
+ width && height ? (React.createElement("span", { className: "placeholder", style: { paddingBottom: `${(height / width) * 100}%` } })) : null,
66
+ child))));
67
+ });
68
+ const ImagePreviewWithSub = assignSubComponent(ImagePreview, {
69
+ displayName: 'ImagePreview',
70
+ });
71
+ export * from './types';
72
+ export default ConfigProvider.config(ImagePreviewWithSub);