botframework-webchat-component 4.19.0 → 4.19.1-main.20260529.6bcfcee

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 (84) hide show
  1. package/dist/_dtsroll-chunks/CwOuXmoL-botframework-webchat-styles.react.d.ts +68 -0
  2. package/dist/botframework-webchat-component.component.d.mts +1 -1
  3. package/dist/botframework-webchat-component.component.d.ts +1 -1
  4. package/dist/botframework-webchat-component.component.js +1 -1
  5. package/dist/botframework-webchat-component.component.mjs +1 -1
  6. package/dist/botframework-webchat-component.d.mts +1 -3
  7. package/dist/botframework-webchat-component.d.ts +1 -3
  8. package/dist/botframework-webchat-component.decorator.js +1 -1
  9. package/dist/botframework-webchat-component.decorator.js.map +1 -1
  10. package/dist/botframework-webchat-component.decorator.mjs +1 -1
  11. package/dist/botframework-webchat-component.decorator.mjs.map +1 -1
  12. package/dist/botframework-webchat-component.hook.js +1 -1
  13. package/dist/botframework-webchat-component.hook.mjs +1 -1
  14. package/dist/botframework-webchat-component.internal.d.mts +2 -6
  15. package/dist/botframework-webchat-component.internal.d.ts +2 -6
  16. package/dist/botframework-webchat-component.internal.js +1 -1
  17. package/dist/botframework-webchat-component.internal.js.map +1 -1
  18. package/dist/botframework-webchat-component.internal.mjs +1 -1
  19. package/dist/botframework-webchat-component.js +1 -1
  20. package/dist/botframework-webchat-component.js.map +1 -1
  21. package/dist/botframework-webchat-component.mjs +1 -1
  22. package/dist/botframework-webchat-component.mjs.map +1 -1
  23. package/dist/chunk-4EA5WZBJ.mjs +80 -0
  24. package/dist/chunk-4EA5WZBJ.mjs.map +1 -0
  25. package/dist/{chunk-H5YR7OLF.js → chunk-B2XHGOQH.js} +2 -2
  26. package/dist/{chunk-H5YR7OLF.js.map → chunk-B2XHGOQH.js.map} +1 -1
  27. package/dist/chunk-C2RHHZZQ.mjs +2 -0
  28. package/dist/chunk-C2RHHZZQ.mjs.map +1 -0
  29. package/dist/{chunk-TYPS3H4I.mjs → chunk-FIPA3BLZ.mjs} +2 -2
  30. package/dist/{chunk-TYPS3H4I.mjs.map → chunk-FIPA3BLZ.mjs.map} +1 -1
  31. package/dist/{chunk-LVVCSDZ4.mjs → chunk-HWDSXHRJ.mjs} +2 -2
  32. package/dist/chunk-JCX7GSY7.js +2 -0
  33. package/dist/{chunk-2R7BJ63Z.js.map → chunk-JCX7GSY7.js.map} +1 -1
  34. package/dist/{chunk-U6OWCHTQ.js → chunk-K4QNZHM5.js} +2 -2
  35. package/dist/chunk-K4QNZHM5.js.map +1 -0
  36. package/dist/{chunk-MOJMHOVH.js → chunk-OJOV52AD.js} +2 -2
  37. package/dist/{chunk-MOJMHOVH.js.map → chunk-OJOV52AD.js.map} +1 -1
  38. package/dist/{chunk-GTOP3WPD.mjs → chunk-WPWJFSZC.mjs} +2 -2
  39. package/dist/chunk-WPWJFSZC.mjs.map +1 -0
  40. package/dist/chunk-ZUKHLDZN.js +80 -0
  41. package/dist/chunk-ZUKHLDZN.js.map +1 -0
  42. package/dist/{component-BtSxgJS5.d.mts → component-BeCWAilk.d.mts} +34 -43
  43. package/dist/{component-Fyy8iCRE.d.ts → component-BtDQyqSP.d.ts} +34 -43
  44. package/dist/metafile-cjs.json +1 -1
  45. package/dist/metafile-esm.json +1 -1
  46. package/package.json +12 -14
  47. package/src/ActivityStatus/SendStatus/private/SendFailedRetry.tsx +31 -0
  48. package/src/BasicToast.js +4 -5
  49. package/src/BasicToaster.js +2 -3
  50. package/src/Composer.tsx +0 -20
  51. package/src/Utils/InlineMarkdown.tsx +121 -0
  52. package/src/Utils/LocalizedString.tsx +123 -124
  53. package/src/Utils/addTargetBlankToHyperlinks.spec.ts +52 -0
  54. package/src/Utils/addTargetBlankToHyperlinks.ts +14 -0
  55. package/src/boot/internal.ts +7 -2
  56. package/src/hooks/internal/WebChatUIContext.ts +0 -2
  57. package/src/hooks/useRenderMarkdownAsHTML.ts +5 -3
  58. package/src/hooks/useStreamingMarkdownWithDefinitions.ts +2 -2
  59. package/src/private/renderMarkdownInline.ts +19 -0
  60. package/src/providers/CustomElements/customElements/CodeBlock.ts +2 -2
  61. package/dist/_dtsroll-chunks/Cha1SOtx-botframework-webchat-styles.react.d.ts +0 -38
  62. package/dist/chunk-2R7BJ63Z.js +0 -2
  63. package/dist/chunk-A4NDFSZM.mjs +0 -77
  64. package/dist/chunk-A4NDFSZM.mjs.map +0 -1
  65. package/dist/chunk-CNTMOACS.mjs +0 -2
  66. package/dist/chunk-CNTMOACS.mjs.map +0 -1
  67. package/dist/chunk-GTOP3WPD.mjs.map +0 -1
  68. package/dist/chunk-U6OWCHTQ.js.map +0 -1
  69. package/dist/chunk-VDF6GQAL.js +0 -77
  70. package/dist/chunk-VDF6GQAL.js.map +0 -1
  71. package/src/ActivityStatus/SendStatus/private/SendFailedRetry.js +0 -28
  72. package/src/Utils/InlineMarkdown.js +0 -154
  73. package/src/Utils/addTargetBlankToHyperlinksMarkdown.js +0 -28
  74. package/src/Utils/addTargetBlankToHyperlinksMarkdown.spec.js +0 -45
  75. package/src/Utils/betterLinks.ts +0 -157
  76. package/src/Utils/parseDocumentFragmentFromString.ts +0 -9
  77. package/src/Utils/serializeDocumentFragmentIntoString.ts +0 -3
  78. package/src/Utils/updateMarkdownAttrs.js +0 -10
  79. package/src/Utils/updateMarkdownAttrs.spec.js +0 -71
  80. package/src/Utils/walkMarkdownTokens.js +0 -15
  81. package/src/Utils/walkMarkdownTokens.spec.js +0 -18
  82. package/src/hooks/internal/useInternalMarkdownIt.js +0 -7
  83. package/src/hooks/internal/useInternalRenderMarkdownInline.js +0 -9
  84. /package/dist/{chunk-LVVCSDZ4.mjs.map → chunk-HWDSXHRJ.mjs.map} +0 -0
@@ -1,28 +0,0 @@
1
- import { hooks } from 'botframework-webchat-api';
2
- import PropTypes from 'prop-types';
3
- import React, { useCallback } from 'react';
4
-
5
- import InlineMarkdown from '../../../Utils/InlineMarkdown';
6
-
7
- const { useLocalizer } = hooks;
8
-
9
- const MARKDOWN_REFERENCES = ['RETRY'];
10
-
11
- const SendFailedRetry = ({ onRetryClick }) => {
12
- const handleReference = useCallback(({ data }) => data === 'RETRY' && onRetryClick(), [onRetryClick]);
13
- const localize = useLocalizer();
14
-
15
- const sendFailedText = localize('ACTIVITY_STATUS_SEND_FAILED_RETRY');
16
-
17
- return (
18
- <InlineMarkdown onReference={handleReference} references={MARKDOWN_REFERENCES}>
19
- {sendFailedText}
20
- </InlineMarkdown>
21
- );
22
- };
23
-
24
- SendFailedRetry.propTypes = {
25
- onRetryClick: PropTypes.func.isRequired
26
- };
27
-
28
- export default SendFailedRetry;
@@ -1,154 +0,0 @@
1
- /* eslint react/no-danger: "off" */
2
-
3
- import { hooks } from 'botframework-webchat-api';
4
- import { isForbiddenPropertyName } from 'botframework-webchat-core';
5
- import PropTypes from 'prop-types';
6
- import React, { useCallback, useMemo } from 'react';
7
- import updateIn from 'simple-update-in';
8
-
9
- import createCustomEvent from './createCustomEvent';
10
- import randomId from './randomId';
11
- import useInternalMarkdownIt from '../hooks/internal/useInternalMarkdownIt';
12
- import { useStyleToEmotionObject } from '../hooks/internal/styleToEmotionObject';
13
- import walkMarkdownTokens from './walkMarkdownTokens';
14
-
15
- const { useStyleOptions } = hooks;
16
-
17
- function replaceAnchorWithButton(markdownTokens) {
18
- return walkMarkdownTokens(markdownTokens, markdownToken => {
19
- markdownToken = { ...markdownToken };
20
-
21
- switch (markdownToken.type) {
22
- case 'link_open':
23
- markdownToken.tag = 'button';
24
- markdownToken.attrs = [
25
- ...updateIn(
26
- markdownToken.attrs,
27
- [([name, value]) => name === 'href' && value.startsWith('#')],
28
- ([, value]) => ['data-markdown-href', value.substr(1)]
29
- ),
30
- ['type', 'button']
31
- ];
32
- break;
33
-
34
- case 'link_close':
35
- markdownToken.tag = 'button';
36
- break;
37
-
38
- default:
39
- break;
40
- }
41
-
42
- return markdownToken;
43
- });
44
- }
45
-
46
- const InlineMarkdown = ({ children, onReference, references }) => {
47
- if (typeof children !== 'string') {
48
- console.warn('botframework-webchat: "children" prop passed to <InlineMarkdown> must be of type string.');
49
-
50
- // Shortcut for disabling invalid props.
51
- // eslint-disable-next-line react-hooks/immutability
52
- children = '';
53
- }
54
-
55
- const [markdownIt] = useInternalMarkdownIt();
56
- const [{ accent }] = useStyleOptions();
57
- const styleToClassName = useStyleToEmotionObject();
58
-
59
- // We inlined the style here because this style is:
60
- // 1. Internal to Web Chat
61
- // 2. Not customizable from developers (other than setting `styleOptions.accent`)
62
- const className = useMemo(
63
- () =>
64
- styleToClassName({
65
- '& button[data-markdown-href]': {
66
- appearance: 'none',
67
- backgroundColor: 'transparent',
68
- border: 0,
69
- color: accent,
70
- cursor: 'pointer',
71
- fontFamily: 'inherit',
72
- fontSize: 'inherit',
73
- padding: 0
74
- },
75
- '@media screen and (forced-colors: active)': {
76
- '& button[data-markdown-href]': {
77
- color: 'LinkText',
78
- textDecoration: 'underline'
79
- }
80
- }
81
- }) + '',
82
- [accent, styleToClassName]
83
- );
84
-
85
- // Markdown-It only support references in uppercase.
86
- // Re-shaping input.
87
- // eslint-disable-next-line react-hooks/immutability
88
- references = references.map(reference => reference.toUpperCase());
89
-
90
- const { hrefToRef, refToHref } = references.reduce(
91
- ({ hrefToRef, refToHref }, ref) => {
92
- const href = randomId();
93
-
94
- return {
95
- hrefToRef: { ...hrefToRef, [href]: ref },
96
- refToHref: { ...refToHref, [ref]: href }
97
- };
98
- },
99
- { hrefToRef: {}, refToHref: {} }
100
- );
101
-
102
- const html = useMemo(() => {
103
- const tree = markdownIt.parseInline(children, {
104
- references: references.reduce(
105
- (references, key) =>
106
- // Mitigated through denylisting.
107
- // eslint-disable-next-line security/detect-object-injection
108
- isForbiddenPropertyName(key) ? references : { ...references, [key]: { href: `#${refToHref[key]}` } },
109
- {}
110
- )
111
- });
112
-
113
- // Turn "<a href="#retry">Retry</a>" into "<button data-ref="retry" type="button">Retry</button>"
114
- const updatedTree = replaceAnchorWithButton(tree);
115
-
116
- return { __html: markdownIt.renderer.render(updatedTree) };
117
- }, [children, refToHref, markdownIt, references]);
118
-
119
- const handleClick = useCallback(
120
- event => {
121
- event.stopPropagation();
122
-
123
- const href = event.target.getAttribute('data-markdown-href');
124
-
125
- href &&
126
- onReference &&
127
- onReference(
128
- createCustomEvent(
129
- 'reference',
130
- // Mitigated through denylisting.
131
- // eslint-disable-next-line security/detect-object-injection
132
- isForbiddenPropertyName(href) ? {} : { data: hrefToRef[href] }
133
- )
134
- );
135
- },
136
- [hrefToRef, onReference]
137
- );
138
-
139
- return <span className={className} dangerouslySetInnerHTML={html} onClick={handleClick} />;
140
- };
141
-
142
- InlineMarkdown.defaultProps = {
143
- children: '',
144
- onReference: undefined,
145
- references: []
146
- };
147
-
148
- InlineMarkdown.propTypes = {
149
- children: PropTypes.string,
150
- onReference: PropTypes.func,
151
- references: PropTypes.arrayOf(PropTypes.string)
152
- };
153
-
154
- export default InlineMarkdown;
@@ -1,28 +0,0 @@
1
- import updateMarkdownAttrs from './updateMarkdownAttrs';
2
- import walkMarkdownTokens from './walkMarkdownTokens';
3
-
4
- export default function addTargetBlankToHyperlinksMarkdown(tokens) {
5
- return walkMarkdownTokens(tokens, token => {
6
- switch (token.type) {
7
- case 'link_open':
8
- token = updateMarkdownAttrs(token, attrs =>
9
- // Adds only for external links, e.g. https://, data:
10
- // Don't add for internal links, e.g. #ref-1, ?q=doc
11
- /^\w/u.test(attrs.href)
12
- ? {
13
- ...attrs,
14
- rel: 'noopener noreferrer',
15
- target: '_blank'
16
- }
17
- : attrs
18
- );
19
-
20
- break;
21
-
22
- default:
23
- break;
24
- }
25
-
26
- return token;
27
- });
28
- }
@@ -1,45 +0,0 @@
1
- import MarkdownIt from 'markdown-it';
2
-
3
- import addTargetBlankToHyperlinksMarkdown from './addTargetBlankToHyperlinksMarkdown';
4
-
5
- test('add to external links', () => {
6
- const markdownIt = new MarkdownIt();
7
- const markdown = 'Hello, [Microsoft](https://microsoft.com/)!';
8
- const tree = markdownIt.parseInline(markdown);
9
- const updatedTree = addTargetBlankToHyperlinksMarkdown(tree);
10
- const html = markdownIt.renderer.render(updatedTree);
11
-
12
- expect(html).toMatchInlineSnapshot(
13
- `"Hello, <a href="https://microsoft.com/" rel="noopener noreferrer" target="_blank">Microsoft</a>!"`
14
- );
15
- });
16
-
17
- test("don't add for hashes", () => {
18
- const markdownIt = new MarkdownIt();
19
- const markdown = 'Hello, [Microsoft](#microsoft)!';
20
- const tree = markdownIt.parseInline(markdown);
21
- const updatedTree = addTargetBlankToHyperlinksMarkdown(tree);
22
- const html = markdownIt.renderer.render(updatedTree);
23
-
24
- expect(html).toMatchInlineSnapshot(`"Hello, <a href="#microsoft">Microsoft</a>!"`);
25
- });
26
-
27
- test("don't add for searches", () => {
28
- const markdownIt = new MarkdownIt();
29
- const markdown = 'Hello, [Microsoft](?q=microsoft)!';
30
- const tree = markdownIt.parseInline(markdown);
31
- const updatedTree = addTargetBlankToHyperlinksMarkdown(tree);
32
- const html = markdownIt.renderer.render(updatedTree);
33
-
34
- expect(html).toMatchInlineSnapshot(`"Hello, <a href="?q=microsoft">Microsoft</a>!"`);
35
- });
36
-
37
- test("don't add for cross references", () => {
38
- const markdownIt = new MarkdownIt();
39
- const markdown = 'Hello, [Microsoft]!';
40
- const tree = markdownIt.parseInline(markdown, { references: { MICROSOFT: { href: '#microsoft' } } });
41
- const updatedTree = addTargetBlankToHyperlinksMarkdown(tree);
42
- const html = markdownIt.renderer.render(updatedTree);
43
-
44
- expect(html).toMatchInlineSnapshot(`"Hello, <a href="#microsoft">Microsoft</a>!"`);
45
- });
@@ -1,157 +0,0 @@
1
- /* eslint-disable security/detect-object-injection */
2
- import MarkdownIt from 'markdown-it';
3
-
4
- function iterator(md, ruleName, tokenType, iterator) {
5
- function scan(state) {
6
- const { env = {} } = state;
7
- for (let blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
8
- if (state.tokens[blkIdx].type !== 'inline') {
9
- continue;
10
- }
11
- const inlineTokens = state.tokens[blkIdx].children;
12
- for (let i = inlineTokens.length - 1; i >= 0; i--) {
13
- if (inlineTokens[i].type !== tokenType) {
14
- continue;
15
- }
16
- iterator(inlineTokens, i, env);
17
- }
18
- }
19
- }
20
- md.core.ruler.push(ruleName, scan);
21
- }
22
-
23
- // Put a transparent pixel instead of the "open in new window" icon, so developers can easily modify the icon in CSS.
24
- const TRANSPARENT_GIF = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
25
-
26
- type AttributeSetter = false | string | ((value?: string) => string);
27
-
28
- export type LinkOptions = {
29
- /** Value of "aria-label" attribute of the link. If set to `false`, remove existing attribute. */
30
- ariaLabel?: AttributeSetter;
31
-
32
- /** Turns this link into a <button> with "value" attribute instead of "href". */
33
- asButton?: boolean;
34
-
35
- /** Value of "class" attribute of the link. If set to `false`, remove existing attribute. */
36
- className?: AttributeSetter;
37
-
38
- /** Alternate text of the image icon appended to the link. */
39
- iconAlt?: string;
40
-
41
- /** Class name of the image icon appended to the link. */
42
- iconClassName?: string;
43
-
44
- /** Value of "rel" attribute of the link. If set to `false`, remove existing attribute. */
45
- rel?: AttributeSetter;
46
-
47
- /** Value of "target" attribute of the link. If set to `false`, remove existing attribute. */
48
- target?: AttributeSetter;
49
-
50
- /** Value of "title" attribute of the link. If set to `false`, remove existing attribute. */
51
- title?: AttributeSetter;
52
-
53
- /** Wraps the link with zero-width space. */
54
- wrapZeroWidthSpace?: boolean;
55
- };
56
-
57
- export type BetterLinkEnv = {
58
- decorateLink?: (href: string, textContent: string, linkOptions: LinkOptions) => LinkOptions | undefined;
59
- linkOptions?: LinkOptions;
60
- };
61
-
62
- // This is used for parsing Markdown for external links.
63
- const internalMarkdownIt = new MarkdownIt();
64
-
65
- const ZERO_WIDTH_SPACE_TOKEN = {
66
- content: '\u200b',
67
- type: 'text'
68
- };
69
-
70
- function setTokenAttribute(attrs: Array<[string, string]>, name: string, value?: AttributeSetter) {
71
- const index = attrs.findIndex(entry => entry[0] === name);
72
-
73
- if (value === false) {
74
- ~index && attrs.splice(index, 1);
75
- } else if (typeof value === 'string') {
76
- if (~index) {
77
- attrs[+index][1] = value;
78
- } else {
79
- attrs.push([name, value]);
80
- }
81
- } else if (typeof value === 'function') {
82
- if (~index) {
83
- attrs[+index][1] = value(attrs[+index][1]);
84
- } else {
85
- attrs.push([name, value()]);
86
- }
87
- }
88
- }
89
-
90
- const betterLinks = (markdown: typeof MarkdownIt): typeof MarkdownIt =>
91
- markdown.use(iterator, 'url_new_win', 'link_open', (tokens, index, env) => {
92
- const { decorateLink, linkOptions }: BetterLinkEnv = env;
93
-
94
- const indexOfLinkCloseToken = tokens.indexOf(tokens.slice(index + 1).find(({ type }) => type === 'link_close'));
95
- // eslint-disable-next-line no-magic-numbers
96
- const updatedTokens = tokens.splice(index, ~indexOfLinkCloseToken ? indexOfLinkCloseToken - index + 1 : 2);
97
-
98
- try {
99
- const [linkOpenToken] = updatedTokens;
100
- const linkCloseToken = updatedTokens[updatedTokens.length - 1];
101
-
102
- const [, href] = linkOpenToken.attrs.find(([name]) => name === 'href');
103
- const nodesInLink = updatedTokens.slice(1, updatedTokens.length - 1);
104
-
105
- const textContent = nodesInLink
106
- .filter(({ type }) => type === 'text')
107
- .map(({ content }) => content)
108
- .join(' ');
109
-
110
- const decoration = decorateLink?.(href, textContent, linkOptions);
111
-
112
- if (!decoration) {
113
- return;
114
- }
115
-
116
- const { ariaLabel, asButton, className, iconAlt, iconClassName, rel, target, title, wrapZeroWidthSpace } =
117
- decoration;
118
-
119
- setTokenAttribute(linkOpenToken.attrs, 'aria-label', ariaLabel);
120
- setTokenAttribute(linkOpenToken.attrs, 'class', className);
121
- setTokenAttribute(linkOpenToken.attrs, 'title', title);
122
-
123
- if (iconClassName) {
124
- const iconTokens = internalMarkdownIt.parseInline(`![](${TRANSPARENT_GIF})`)[0].children;
125
-
126
- setTokenAttribute(iconTokens[0].attrs, 'class', iconClassName);
127
- setTokenAttribute(iconTokens[0].attrs, 'title', iconAlt);
128
-
129
- // Add an icon before </a>.
130
- // eslint-disable-next-line no-magic-numbers
131
- updatedTokens.splice(-1, 0, ...iconTokens);
132
- }
133
-
134
- if (asButton) {
135
- setTokenAttribute(linkOpenToken.attrs, 'href', false);
136
-
137
- linkOpenToken.tag = 'button';
138
-
139
- setTokenAttribute(linkOpenToken.attrs, 'type', 'button');
140
- setTokenAttribute(linkOpenToken.attrs, 'value', href);
141
-
142
- linkCloseToken.tag = 'button';
143
- } else {
144
- setTokenAttribute(linkOpenToken.attrs, 'rel', rel);
145
- setTokenAttribute(linkOpenToken.attrs, 'target', target);
146
- }
147
-
148
- if (wrapZeroWidthSpace) {
149
- updatedTokens.splice(0, 0, ZERO_WIDTH_SPACE_TOKEN);
150
- updatedTokens.splice(Infinity, 0, ZERO_WIDTH_SPACE_TOKEN);
151
- }
152
- } finally {
153
- tokens.splice(index, 0, ...updatedTokens);
154
- }
155
- });
156
-
157
- export default betterLinks;
@@ -1,9 +0,0 @@
1
- export default function parseDocumentFragmentFromString(html: string): DocumentFragment {
2
- const parser = new DOMParser();
3
- const parsedDocument = parser.parseFromString(html, 'text/html');
4
- const fragment = parsedDocument.createDocumentFragment();
5
-
6
- fragment.append(...parsedDocument.body.childNodes);
7
-
8
- return fragment;
9
- }
@@ -1,3 +0,0 @@
1
- export default function serializeDocumentFragmentIntoString(documentFragment: DocumentFragment): string {
2
- return new XMLSerializer().serializeToString(documentFragment);
3
- }
@@ -1,10 +0,0 @@
1
- import updateIn from 'simple-update-in';
2
-
3
- export default function updateMarkdownItAttrs(token, updater) {
4
- return updateIn(token, ['attrs'], attrs => {
5
- const map = Object.fromEntries(attrs);
6
- const nextMap = updater(map);
7
-
8
- return Object.entries(nextMap);
9
- });
10
- }
@@ -1,71 +0,0 @@
1
- import updateMarkdownAttrs from './updateMarkdownAttrs';
2
-
3
- test('add "rel" and "target" attributes', () => {
4
- const token = {
5
- attrs: [['href', 'https://example.org/']]
6
- };
7
-
8
- const actual = updateMarkdownAttrs(token, attrs => ({ ...attrs, rel: 'noopener noreferrer', target: '_blank' }));
9
-
10
- expect(actual).toMatchInlineSnapshot(`
11
- {
12
- "attrs": [
13
- [
14
- "href",
15
- "https://example.org/",
16
- ],
17
- [
18
- "rel",
19
- "noopener noreferrer",
20
- ],
21
- [
22
- "target",
23
- "_blank",
24
- ],
25
- ],
26
- }
27
- `);
28
-
29
- // The token passed in should kept unchanged
30
- expect(token).toMatchInlineSnapshot(`
31
- {
32
- "attrs": [
33
- [
34
- "href",
35
- "https://example.org/",
36
- ],
37
- ],
38
- }
39
- `);
40
- });
41
-
42
- test('replace "href" attribute', () => {
43
- const token = {
44
- attrs: [['href', 'https://example.org/']]
45
- };
46
-
47
- const actual = updateMarkdownAttrs(token, () => ({ href: 'https://microsoft.com/' }));
48
-
49
- expect(actual).toMatchInlineSnapshot(`
50
- {
51
- "attrs": [
52
- [
53
- "href",
54
- "https://microsoft.com/",
55
- ],
56
- ],
57
- }
58
- `);
59
-
60
- // The token passed in should kept unchanged
61
- expect(token).toMatchInlineSnapshot(`
62
- {
63
- "attrs": [
64
- [
65
- "href",
66
- "https://example.org/",
67
- ],
68
- ],
69
- }
70
- `);
71
- });
@@ -1,15 +0,0 @@
1
- export default function walkMarkdownTokens(tokens, walker) {
2
- return tokens.map(token => {
3
- if (token) {
4
- const nextToken = walker(token);
5
-
6
- if (nextToken.children) {
7
- nextToken.children = walkMarkdownTokens(nextToken.children, walker);
8
- }
9
-
10
- return nextToken;
11
- }
12
-
13
- return token;
14
- });
15
- }
@@ -1,18 +0,0 @@
1
- import MarkdownIt from 'markdown-it';
2
- import updateIn from 'simple-update-in';
3
-
4
- import walkMarkdownTokens from './walkMarkdownTokens';
5
-
6
- test('walk every node and add class="markdown"', () => {
7
- const markdownIt = new MarkdownIt();
8
- const tree = markdownIt.parse('Hello, [World](#world)!');
9
- const patchedTree = walkMarkdownTokens(tree, token =>
10
- updateIn(token, ['attrs'], attrs => [...(attrs || []), ['class', 'markdown']])
11
- );
12
- const actual = markdownIt.renderer.render(patchedTree);
13
-
14
- expect(actual).toMatchInlineSnapshot(`
15
- "<p class="markdown">Hello, <a href="#world" class="markdown">World</a class="markdown">!</p class="markdown">
16
- "
17
- `);
18
- });
@@ -1,7 +0,0 @@
1
- import useWebChatUIContext from './useWebChatUIContext';
2
-
3
- function useInternalMarkdownIt() {
4
- return useWebChatUIContext().internalMarkdownItState;
5
- }
6
-
7
- export default useInternalMarkdownIt;
@@ -1,9 +0,0 @@
1
- import useWebChatUIContext from './useWebChatUIContext';
2
-
3
- function useInternalRenderMarkdownInline() {
4
- const { internalRenderMarkdownInline } = useWebChatUIContext();
5
-
6
- return internalRenderMarkdownInline;
7
- }
8
-
9
- export default useInternalRenderMarkdownInline;