@patternfly/chatbot 6.4.0-prerelease.19 → 6.4.0-prerelease.20
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.
- package/dist/cjs/Message/LinkMessage/LinkMessage.d.ts +2 -1
- package/dist/cjs/Message/LinkMessage/LinkMessage.js +7 -3
- package/dist/cjs/Message/ListMessage/ListItemMessage.d.ts +1 -1
- package/dist/cjs/Message/ListMessage/ListItemMessage.js +16 -1
- package/dist/cjs/Message/Message.d.ts +4 -0
- package/dist/cjs/Message/Message.js +111 -22
- package/dist/cjs/Message/Message.test.js +35 -0
- package/dist/cjs/Message/SuperscriptMessage/SuperscriptMessage.d.ts +3 -0
- package/dist/cjs/Message/SuperscriptMessage/SuperscriptMessage.js +5 -0
- package/dist/css/main.css +142 -12
- package/dist/css/main.css.map +1 -1
- package/dist/esm/Message/LinkMessage/LinkMessage.d.ts +2 -1
- package/dist/esm/Message/LinkMessage/LinkMessage.js +7 -3
- package/dist/esm/Message/ListMessage/ListItemMessage.d.ts +1 -1
- package/dist/esm/Message/ListMessage/ListItemMessage.js +16 -1
- package/dist/esm/Message/Message.d.ts +4 -0
- package/dist/esm/Message/Message.js +111 -22
- package/dist/esm/Message/Message.test.js +35 -0
- package/dist/esm/Message/SuperscriptMessage/SuperscriptMessage.d.ts +3 -0
- package/dist/esm/Message/SuperscriptMessage/SuperscriptMessage.js +3 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +101 -3
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +107 -2
- package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +2 -1
- package/src/Message/LinkMessage/LinkMessage.tsx +6 -2
- package/src/Message/ListMessage/ListItemMessage.tsx +5 -1
- package/src/Message/ListMessage/ListMessage.scss +17 -0
- package/src/Message/Message.scss +44 -0
- package/src/Message/Message.test.tsx +36 -0
- package/src/Message/Message.tsx +127 -28
- package/src/Message/SuperscriptMessage/SuperscriptMessage.scss +8 -0
- package/src/Message/SuperscriptMessage/SuperscriptMessage.tsx +13 -0
- package/src/Message/TextMessage/TextMessage.scss +46 -5
|
@@ -16,10 +16,14 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
16
16
|
import { Button } from '@patternfly/react-core';
|
|
17
17
|
import { ExternalLinkSquareAltIcon } from '@patternfly/react-icons';
|
|
18
18
|
const LinkMessage = (_a) => {
|
|
19
|
-
var { children, target, href } = _a, props = __rest(_a, ["children", "target", "href"]);
|
|
19
|
+
var { children, target, href, id } = _a, props = __rest(_a, ["children", "target", "href", "id"]);
|
|
20
20
|
if (target === '_blank') {
|
|
21
|
-
return (_jsx(Button, Object.assign({ component: "a", variant: "link", href: href, icon: _jsx(ExternalLinkSquareAltIcon, {}), iconPosition: "end", isInline: true, target: target
|
|
21
|
+
return (_jsx(Button, Object.assign({ component: "a", variant: "link", href: href, icon: _jsx(ExternalLinkSquareAltIcon, {}), iconPosition: "end", isInline: true, target: target,
|
|
22
|
+
// need to explicitly call this out or id doesn't seem to get passed - required for footnotes
|
|
23
|
+
id: id }, props, { children: children })));
|
|
22
24
|
}
|
|
23
|
-
return (
|
|
25
|
+
return (
|
|
26
|
+
// need to explicitly call this out or id doesn't seem to get passed - required for footnotes
|
|
27
|
+
_jsx(Button, Object.assign({ isInline: true, component: "a", href: href, variant: "link", id: id }, props, { children: children })));
|
|
24
28
|
};
|
|
25
29
|
export default LinkMessage;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { ExtraProps } from 'react-markdown';
|
|
2
|
-
declare const ListItemMessage: ({ children }: JSX.IntrinsicElements["li"] & ExtraProps) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
declare const ListItemMessage: ({ children, ...props }: JSX.IntrinsicElements["li"] & ExtraProps) => import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
export default ListItemMessage;
|
|
@@ -1,4 +1,19 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
1
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
13
|
import { ListItem } from '@patternfly/react-core';
|
|
3
|
-
const ListItemMessage = (
|
|
14
|
+
const ListItemMessage = (_a) => {
|
|
15
|
+
var _b;
|
|
16
|
+
var { children } = _a, props = __rest(_a, ["children"]);
|
|
17
|
+
return (_jsx(ListItem, Object.assign({}, props, { tabIndex: ((_b = props === null || props === void 0 ? void 0 : props.id) === null || _b === void 0 ? void 0 : _b.includes('fn-')) ? -1 : props === null || props === void 0 ? void 0 : props.tabIndex, children: children })));
|
|
18
|
+
};
|
|
4
19
|
export default ListItemMessage;
|
|
@@ -119,6 +119,8 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
|
|
|
119
119
|
tableProps?: Required<Pick<TableProps, 'aria-label'>> & TableProps;
|
|
120
120
|
/** Additional rehype plugins passed from the consumer */
|
|
121
121
|
additionalRehypePlugins?: PluggableList;
|
|
122
|
+
/** Additional remark plugins passed from the consumer */
|
|
123
|
+
additionalRemarkPlugins?: PluggableList;
|
|
122
124
|
/** Whether to open links in message in new tab. */
|
|
123
125
|
openLinkInNewTab?: boolean;
|
|
124
126
|
/** Optional inline error message that can be displayed in the message */
|
|
@@ -151,6 +153,8 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
|
|
|
151
153
|
toolResponse?: ToolResponseProps;
|
|
152
154
|
/** Props for deep thinking card */
|
|
153
155
|
deepThinking?: DeepThinkingProps;
|
|
156
|
+
/** Allows passing additional props down to remark-gfm. See https://github.com/remarkjs/remark-gfm?tab=readme-ov-file#options for options */
|
|
157
|
+
remarkGfmProps?: Options;
|
|
154
158
|
}
|
|
155
159
|
export declare const MessageBase: FunctionComponent<MessageProps>;
|
|
156
160
|
declare const Message: import("react").ForwardRefExoticComponent<Omit<MessageProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -46,8 +46,9 @@ import MessageInput from './MessageInput';
|
|
|
46
46
|
import { rehypeMoveImagesOutOfParagraphs } from './Plugins/rehypeMoveImagesOutOfParagraphs';
|
|
47
47
|
import ToolResponse from '../ToolResponse';
|
|
48
48
|
import DeepThinking from '../DeepThinking';
|
|
49
|
+
import SuperscriptMessage from './SuperscriptMessage/SuperscriptMessage';
|
|
49
50
|
export const MessageBase = (_a) => {
|
|
50
|
-
var { role, content, extraContent, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps, quickStarts, userFeedbackForm, userFeedbackComplete, isLiveRegion = true, innerRef, tableProps, openLinkInNewTab = true, additionalRehypePlugins = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, inputRef, editFormProps, isCompact, isMarkdownDisabled, reactMarkdownProps, toolResponse, deepThinking } = _a, props = __rest(_a, ["role", "content", "extraContent", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps", "quickStarts", "userFeedbackForm", "userFeedbackComplete", "isLiveRegion", "innerRef", "tableProps", "openLinkInNewTab", "additionalRehypePlugins", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "inputRef", "editFormProps", "isCompact", "isMarkdownDisabled", "reactMarkdownProps", "toolResponse", "deepThinking"]);
|
|
51
|
+
var { role, content, extraContent, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps, quickStarts, userFeedbackForm, userFeedbackComplete, isLiveRegion = true, innerRef, tableProps, openLinkInNewTab = true, additionalRehypePlugins = [], additionalRemarkPlugins = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, inputRef, editFormProps, isCompact, isMarkdownDisabled, reactMarkdownProps, toolResponse, deepThinking, remarkGfmProps } = _a, props = __rest(_a, ["role", "content", "extraContent", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps", "quickStarts", "userFeedbackForm", "userFeedbackComplete", "isLiveRegion", "innerRef", "tableProps", "openLinkInNewTab", "additionalRehypePlugins", "additionalRemarkPlugins", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "inputRef", "editFormProps", "isCompact", "isMarkdownDisabled", "reactMarkdownProps", "toolResponse", "deepThinking", "remarkGfmProps"]);
|
|
51
52
|
const [messageText, setMessageText] = useState(content);
|
|
52
53
|
useEffect(() => {
|
|
53
54
|
setMessageText(content);
|
|
@@ -74,35 +75,123 @@ export const MessageBase = (_a) => {
|
|
|
74
75
|
return (_jsx(TextMessage, Object.assign({ component: ContentVariants.p }, props, { children: messageText })));
|
|
75
76
|
}
|
|
76
77
|
return (_jsx(Markdown, Object.assign({ components: {
|
|
77
|
-
|
|
78
|
+
section: (props) => {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
80
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
81
|
+
return _jsx("section", Object.assign({}, rest, { className: `pf-chatbot__message-text ${rest === null || rest === void 0 ? void 0 : rest.className}` }));
|
|
82
|
+
},
|
|
83
|
+
p: (props) => {
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
85
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
86
|
+
return _jsx(TextMessage, Object.assign({ component: ContentVariants.p }, rest));
|
|
87
|
+
},
|
|
78
88
|
code: (_a) => {
|
|
79
89
|
var { children } = _a, props = __rest(_a, ["children"]);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
91
|
+
const { node } = props, codeProps = __rest(props, ["node"]);
|
|
92
|
+
return (_jsx(CodeBlockMessage, Object.assign({}, codeProps, codeBlockProps, { children: children })));
|
|
93
|
+
},
|
|
94
|
+
h1: (props) => {
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
96
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
97
|
+
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h1 }, rest));
|
|
98
|
+
},
|
|
99
|
+
h2: (props) => {
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
101
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
102
|
+
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h2 }, rest));
|
|
103
|
+
},
|
|
104
|
+
h3: (props) => {
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
106
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
107
|
+
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h3 }, rest));
|
|
108
|
+
},
|
|
109
|
+
h4: (props) => {
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
111
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
112
|
+
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h4 }, rest));
|
|
113
|
+
},
|
|
114
|
+
h5: (props) => {
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
116
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
117
|
+
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h5 }, rest));
|
|
118
|
+
},
|
|
119
|
+
h6: (props) => {
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
121
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
122
|
+
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h6 }, rest));
|
|
123
|
+
},
|
|
124
|
+
blockquote: (props) => {
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
126
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
127
|
+
return _jsx(TextMessage, Object.assign({ component: ContentVariants.blockquote }, rest));
|
|
128
|
+
},
|
|
129
|
+
ul: (props) => {
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
131
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
132
|
+
return _jsx(UnorderedListMessage, Object.assign({}, rest));
|
|
133
|
+
},
|
|
134
|
+
ol: (props) => {
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
136
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
137
|
+
return _jsx(OrderedListMessage, Object.assign({}, rest));
|
|
138
|
+
},
|
|
139
|
+
li: (props) => {
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
141
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
142
|
+
return _jsx(ListItemMessage, Object.assign({}, rest));
|
|
143
|
+
},
|
|
144
|
+
// table requires node attribute for calculating headers for mobile breakpoint
|
|
92
145
|
table: (props) => _jsx(TableMessage, Object.assign({}, props, tableProps)),
|
|
93
|
-
tbody: (props) =>
|
|
94
|
-
|
|
95
|
-
|
|
146
|
+
tbody: (props) => {
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
148
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
149
|
+
return _jsx(TbodyMessage, Object.assign({}, rest));
|
|
150
|
+
},
|
|
151
|
+
thead: (props) => {
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
153
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
154
|
+
return _jsx(TheadMessage, Object.assign({}, rest));
|
|
155
|
+
},
|
|
156
|
+
tr: (props) => {
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
158
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
159
|
+
return _jsx(TrMessage, Object.assign({}, rest));
|
|
160
|
+
},
|
|
96
161
|
td: (props) => {
|
|
97
162
|
// Conflicts with Td type
|
|
98
163
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
99
|
-
const { width } = props, rest = __rest(props, ["width"]);
|
|
164
|
+
const { node, width } = props, rest = __rest(props, ["node", "width"]);
|
|
100
165
|
return _jsx(TdMessage, Object.assign({}, rest));
|
|
101
166
|
},
|
|
102
|
-
th: (props) =>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
167
|
+
th: (props) => {
|
|
168
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
169
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
170
|
+
return _jsx(ThMessage, Object.assign({}, rest));
|
|
171
|
+
},
|
|
172
|
+
img: (props) => {
|
|
173
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
174
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
175
|
+
return _jsx(ImageMessage, Object.assign({}, rest));
|
|
176
|
+
},
|
|
177
|
+
a: (props) => {
|
|
178
|
+
// node is just the details of the document structure - not needed
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
180
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
181
|
+
return (
|
|
182
|
+
// some a types conflict with ButtonProps, but it's ok because we are using an a tag
|
|
183
|
+
// there are too many to handle manually
|
|
184
|
+
_jsx(LinkMessage, Object.assign({}, rest, linkProps, { children: props.children })));
|
|
185
|
+
},
|
|
186
|
+
// used for footnotes
|
|
187
|
+
sup: (props) => {
|
|
188
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
189
|
+
const { node } = props, rest = __rest(props, ["node"]);
|
|
190
|
+
return _jsx(SuperscriptMessage, Object.assign({}, rest));
|
|
191
|
+
}
|
|
192
|
+
}, remarkPlugins: [[remarkGfm, Object.assign({}, remarkGfmProps)], ...additionalRemarkPlugins], rehypePlugins: rehypePlugins }, reactMarkdownProps, { remarkRehypeOptions: Object.assign({
|
|
193
|
+
// removes sr-only class from footnote labels applied by default
|
|
194
|
+
footnoteLabelProperties: { className: [''] } }, reactMarkdownProps === null || reactMarkdownProps === void 0 ? void 0 : reactMarkdownProps.remarkRehypeOptions), children: messageText })));
|
|
106
195
|
};
|
|
107
196
|
const renderMessage = () => {
|
|
108
197
|
if (isLoading) {
|
|
@@ -136,6 +136,19 @@ const EMPTY_TABLE = `
|
|
|
136
136
|
| |
|
|
137
137
|
|
|
138
138
|
`;
|
|
139
|
+
const FOOTNOTE = `This is some text with a footnote[^1] and here's a longer one.[^bignote]
|
|
140
|
+
|
|
141
|
+
You can also reference the same footnote multiple times[^1].
|
|
142
|
+
|
|
143
|
+
[^1]: This is the full footnote text. You can click the arrow to go back up.
|
|
144
|
+
|
|
145
|
+
[^bignote]: Here's one with multiple paragraphs and **formatting**.
|
|
146
|
+
|
|
147
|
+
Indent paragraphs to include them in the footnote.
|
|
148
|
+
|
|
149
|
+
Add as many paragraphs as you like. You can include *italic text*, **bold text**, and even \`code\`.
|
|
150
|
+
|
|
151
|
+
> You can even include blockquotes in footnotes!`;
|
|
139
152
|
const IMAGE = ``;
|
|
140
153
|
const INLINE_IMAGE = `inline text `;
|
|
141
154
|
const DEEP_THINKING = {
|
|
@@ -605,6 +618,28 @@ describe('Message', () => {
|
|
|
605
618
|
render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: TABLE, tableProps: { 'aria-label': 'Test' } }));
|
|
606
619
|
expect(screen.getByRole('grid', { name: /Test/i })).toBeTruthy();
|
|
607
620
|
});
|
|
621
|
+
it('should render footnote correctly', () => {
|
|
622
|
+
render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: FOOTNOTE }));
|
|
623
|
+
expect(screen.getByText(/This is some text with a footnote/i)).toBeTruthy();
|
|
624
|
+
expect(screen.getByText(/and here's a longer one./i)).toBeTruthy();
|
|
625
|
+
expect(screen.getByText(/You can also reference the same footnote multiple times./i)).toBeTruthy();
|
|
626
|
+
expect(screen.getByRole('heading', { name: /Footnotes/i })).toBeTruthy();
|
|
627
|
+
expect(screen.getByText(/This is the full footnote text. You can click the arrow to go back up./i)).toBeTruthy();
|
|
628
|
+
expect(screen.getByText(/Here's one with multiple paragraphs and/i)).toBeTruthy();
|
|
629
|
+
expect(screen.getByText(/formatting/i)).toBeTruthy();
|
|
630
|
+
expect(screen.getByText(/Indent paragraphs to include them in the footnote./i)).toBeTruthy();
|
|
631
|
+
expect(screen.getByText(/Add as many paragraphs as you like. You can include/i)).toBeTruthy();
|
|
632
|
+
expect(screen.getByText(/italic text/i)).toBeTruthy();
|
|
633
|
+
expect(screen.getByText(/bold text/i)).toBeTruthy();
|
|
634
|
+
expect(screen.getByText(/, and even/i)).toBeTruthy();
|
|
635
|
+
expect(screen.getByText(/code/i)).toBeTruthy();
|
|
636
|
+
expect(screen.getByText(/You can even include blockquotes in footnotes!/i)).toBeTruthy();
|
|
637
|
+
expect(screen.getAllByRole('link', { name: '1' })).toHaveLength(2);
|
|
638
|
+
expect(screen.getAllByRole('link', { name: '2' })).toBeTruthy();
|
|
639
|
+
expect(screen.getByRole('link', { name: 'Back to reference 1' })).toBeTruthy();
|
|
640
|
+
expect(screen.getByRole('link', { name: 'Back to reference 1-2' })).toBeTruthy();
|
|
641
|
+
expect(screen.getByRole('link', { name: /Back to reference 2/i })).toBeTruthy();
|
|
642
|
+
});
|
|
608
643
|
it('should render beforeMainContent with main content', () => {
|
|
609
644
|
const mainContent = 'Main message content';
|
|
610
645
|
const beforeMainContentText = 'Before main content';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
|
|
1
|
+
{"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/SuperscriptMessage/SuperscriptMessage.tsx","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/chatbot",
|
|
3
|
-
"version": "6.4.0-prerelease.
|
|
3
|
+
"version": "6.4.0-prerelease.20",
|
|
4
4
|
"description": "This library provides React components based on PatternFly 6 that can be used to build chatbots.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CSSProperties,
|
|
3
|
+
useState,
|
|
4
|
+
Fragment,
|
|
5
|
+
FunctionComponent,
|
|
6
|
+
MouseEvent as ReactMouseEvent,
|
|
7
|
+
KeyboardEvent as ReactKeyboardEvent,
|
|
8
|
+
Ref
|
|
9
|
+
} from 'react';
|
|
2
10
|
import Message from '@patternfly/chatbot/dist/dynamic/Message';
|
|
3
11
|
import patternflyAvatar from './patternfly_avatar.jpg';
|
|
4
12
|
import squareImg from './PF-social-color-square.svg';
|
|
@@ -44,6 +52,8 @@ export const BotMessageExample: FunctionComponent = () => {
|
|
|
44
52
|
return table;
|
|
45
53
|
case 'Image':
|
|
46
54
|
return image;
|
|
55
|
+
case 'Footnote':
|
|
56
|
+
return footnote;
|
|
47
57
|
default:
|
|
48
58
|
return;
|
|
49
59
|
}
|
|
@@ -150,6 +160,18 @@ _Italic text, formatted with single underscores_
|
|
|
150
160
|
|
|
151
161
|
const image = ``;
|
|
152
162
|
|
|
163
|
+
const footnote = `This is some text that has a short footnote[^1] and this is text with a longer footnote.[^bignote]
|
|
164
|
+
|
|
165
|
+
[^1]: This is a short footnote. To return the highlight to the original message, click the arrow.
|
|
166
|
+
|
|
167
|
+
[^bignote]: This is a long footnote with multiple paragraphs and formatting.
|
|
168
|
+
|
|
169
|
+
To break long footnotes into paragraphs, indent the text.
|
|
170
|
+
|
|
171
|
+
Add as many paragraphs as you like. You can include *italic text*, **bold text**, and \`code\`.
|
|
172
|
+
|
|
173
|
+
> You can even include blockquotes in footnotes!`;
|
|
174
|
+
|
|
153
175
|
const error = {
|
|
154
176
|
title: 'Could not load chat',
|
|
155
177
|
children: 'Wait a few minutes and check your network settings. If the issue persists: ',
|
|
@@ -165,8 +187,8 @@ _Italic text, formatted with single underscores_
|
|
|
165
187
|
)
|
|
166
188
|
};
|
|
167
189
|
|
|
168
|
-
const onSelect = (_event:
|
|
169
|
-
setVariant(value);
|
|
190
|
+
const onSelect = (_event: ReactMouseEvent<Element, MouseEvent> | undefined, value: string | number | undefined) => {
|
|
191
|
+
setVariant(value as string);
|
|
170
192
|
setSelected(value as string);
|
|
171
193
|
setIsOpen(false);
|
|
172
194
|
if (value === 'Expandable code') {
|
|
@@ -196,6 +218,76 @@ _Italic text, formatted with single underscores_
|
|
|
196
218
|
</MenuToggle>
|
|
197
219
|
);
|
|
198
220
|
|
|
221
|
+
const handleFootnoteNavigation = (event: ReactMouseEvent<HTMLElement> | ReactKeyboardEvent<HTMLElement>) => {
|
|
222
|
+
const target = event.target as HTMLElement;
|
|
223
|
+
|
|
224
|
+
// Depending on whether it is a click event or keyboard event, target may be a link or something like a span
|
|
225
|
+
// Look for the closest anchor element (could be a parent)
|
|
226
|
+
const anchorElement = target.closest('a');
|
|
227
|
+
const href = anchorElement?.getAttribute('href');
|
|
228
|
+
|
|
229
|
+
// Check if this is a footnote link - we only have internal links in this example, so this is all we need here
|
|
230
|
+
if (href && href.startsWith('#')) {
|
|
231
|
+
// Prevent default behavior to avoid page re-render on click in PatternFly docs framework
|
|
232
|
+
event.preventDefault();
|
|
233
|
+
|
|
234
|
+
let targetElement: HTMLElement | null = null;
|
|
235
|
+
const targetId = href.replace('#', '');
|
|
236
|
+
targetElement = document.querySelector(`[id="${targetId}"]`);
|
|
237
|
+
|
|
238
|
+
if (targetElement) {
|
|
239
|
+
let focusTarget = targetElement;
|
|
240
|
+
|
|
241
|
+
// If we found a footnote definition container, focus on the parent li element
|
|
242
|
+
if (targetElement.id?.startsWith('bot-message-fn-')) {
|
|
243
|
+
// Find the parent li element that contains the footnote
|
|
244
|
+
const parentLi = targetElement.closest('li');
|
|
245
|
+
if (parentLi) {
|
|
246
|
+
focusTarget = parentLi as HTMLElement;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
focusTarget.focus();
|
|
251
|
+
|
|
252
|
+
let elementToHighlight = targetElement;
|
|
253
|
+
|
|
254
|
+
// If this is a backref link (going back to footnote reference),
|
|
255
|
+
// we want to highlight more of the ref line and not just the link itself
|
|
256
|
+
// since the target is so small
|
|
257
|
+
if (targetElement.id?.startsWith('bot-message-fnref-')) {
|
|
258
|
+
const refLink = targetElement;
|
|
259
|
+
|
|
260
|
+
// Walk up the DOM to find a meaningful container
|
|
261
|
+
let parent = refLink.parentElement;
|
|
262
|
+
while (parent && parent.tagName.toLowerCase() !== 'p' && parent !== document.body) {
|
|
263
|
+
parent = parent.parentElement;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Use if found, otherwise use the immediate parent or target as a fallback
|
|
267
|
+
elementToHighlight = parent || refLink.parentElement || targetElement;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Briefly highlight the target element for fun to show what you can do
|
|
271
|
+
const originalBackground = elementToHighlight.style.backgroundColor;
|
|
272
|
+
const originalTransition = elementToHighlight.style.transition;
|
|
273
|
+
|
|
274
|
+
elementToHighlight.style.transition = 'background-color 0.3s ease';
|
|
275
|
+
elementToHighlight.style.backgroundColor = 'var(--pf-t--global--background--color--tertiary--default)';
|
|
276
|
+
|
|
277
|
+
setTimeout(() => {
|
|
278
|
+
elementToHighlight.style.backgroundColor = originalBackground;
|
|
279
|
+
setTimeout(() => {
|
|
280
|
+
elementToHighlight.style.transition = originalTransition;
|
|
281
|
+
}, 300);
|
|
282
|
+
}, 1000);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const onClick = (event: ReactMouseEvent<HTMLElement> | ReactKeyboardEvent<HTMLElement>) => {
|
|
288
|
+
handleFootnoteNavigation(event);
|
|
289
|
+
};
|
|
290
|
+
|
|
199
291
|
return (
|
|
200
292
|
<>
|
|
201
293
|
<Message
|
|
@@ -248,6 +340,7 @@ _Italic text, formatted with single underscores_
|
|
|
248
340
|
<SelectOption value="More complex list">More complex list</SelectOption>
|
|
249
341
|
<SelectOption value="Table">Table</SelectOption>
|
|
250
342
|
<SelectOption value="Image">Image</SelectOption>
|
|
343
|
+
<SelectOption value="Footnote">Footnote</SelectOption>
|
|
251
344
|
<SelectOption value="Error">Error</SelectOption>
|
|
252
345
|
</SelectList>
|
|
253
346
|
</Select>
|
|
@@ -265,6 +358,11 @@ _Italic text, formatted with single underscores_
|
|
|
265
358
|
// The purpose of this plugin is to provide unique link names for the code blocks
|
|
266
359
|
// Because they are in the same message, this requires a custom plugin to parse the syntax tree
|
|
267
360
|
additionalRehypePlugins={[rehypeCodeBlockToggle]}
|
|
361
|
+
linkProps={{ onClick }}
|
|
362
|
+
// clobberPrefix controls the label ids
|
|
363
|
+
reactMarkdownProps={{
|
|
364
|
+
remarkRehypeOptions: { footnoteLabel: 'Bot message footnotes', clobberPrefix: 'bot-message-' }
|
|
365
|
+
}}
|
|
268
366
|
/>
|
|
269
367
|
</>
|
|
270
368
|
);
|