From da112f46601918dc605b4a170919724e10a09cd3 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Tue, 5 Nov 2024 09:42:19 -0500 Subject: [PATCH 01/11] feat(SkipToContent): Add SkipToContent to demos --- .../examples/demos/Chatbot.md | 4 +++- .../examples/demos/Chatbot.tsx | 15 ++++++++++++- .../examples/demos/EmbeddedChatbot.tsx | 21 ++++++++++++++++--- packages/module/src/Chatbot/Chatbot.tsx | 4 +++- .../src/ChatbotToggle/ChatbotToggle.tsx | 15 +++++++------ packages/module/src/MessageBox/MessageBox.tsx | 19 ++++++++++++++--- 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md index 49959439..957fdde1 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md @@ -77,6 +77,8 @@ This demo displays a basic chatbot, which includes: 6. A [``](/patternfly-ai/chatbot/chatbot-conversation-history) toggled open and closed by the ` in the ``. +7. A skip to chatbot link, made with a [PatternFly 6 Skip to Content](/components/skip-to-content) + ```js file="./Chatbot.tsx" isFullscreen ``` @@ -85,7 +87,7 @@ This demo displays a basic chatbot, which includes: This demo displays an embedded chatbot. Embedded chatbots are meant to be placed within a page in your product. This demo includes: -1. A [PatternFly page](/components/page) with a sidebar and masthead +1. A [PatternFly page](/components/page) with a sidebar, skip to chatbot link, and masthead 2. A [``](/patternfly-ai/chatbot/chatbot-container) container. 3. A [``](/patternfly-ai/chatbot/chatbot-header) with all built sub-components laid out, including a `` 4. [`` and ``](/patternfly-ai/chatbot/chatbot-container#content-and-message-box) with: diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx index c40667a3..c9f3cfea 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Bullseye, Brand, DropdownList, DropdownItem, DropdownGroup } from '@patternfly/react-core'; +import { Bullseye, Brand, DropdownList, DropdownItem, DropdownGroup, SkipToContent } from '@patternfly/react-core'; import ChatbotToggle from '@patternfly/virtual-assistant/dist/dynamic/ChatbotToggle'; import Chatbot, { ChatbotDisplayMode } from '@patternfly/virtual-assistant/dist/dynamic/Chatbot'; @@ -175,6 +175,7 @@ export const ChatbotDemo: React.FunctionComponent = () => { ); const [announcement, setAnnouncement] = React.useState(); const scrollToBottomRef = React.useRef(null); + const toggleRef = React.useRef(null); // Autu-scrolls to the latest message React.useEffect(() => { @@ -299,12 +300,24 @@ export const ChatbotDemo: React.FunctionComponent = () => { ); + const handleSkipToContent = (e) => { + e.preventDefault(); + if (toggleRef.current) { + toggleRef.current.focus(); + } + }; + return ( <> + + Skip to chatbot + setChatbotVisible(!chatbotVisible)} + id="chatbot-toggle" + ref={toggleRef} /> { const [isSidebarOpen, setIsSidebarOpen] = React.useState(false); const [announcement, setAnnouncement] = React.useState(); const scrollToBottomRef = React.useRef(null); + const chatbotRef = React.useRef(null); + const displayMode = ChatbotDisplayMode.embedded; // Autu-scrolls to the latest message React.useEffect(() => { @@ -320,8 +323,20 @@ export const EmbeddedChatbotDemo: React.FunctionComponent = () => { ); + const skipToChatbot = (event: React.MouseEvent) => { + event.preventDefault(); + chatbotRef.current?.focus(); + }; + + const skipToContent = ( + /* You can also add a SkipToContent for your main content here */ + + Skip to chatbot + + ); + return ( - + { {/* Update the announcement prop on MessageBox whenever a new message is sent so that users of assistive devices receive sufficient context */} - + = ({ children, displayMode = ChatbotDisplayMode.default, isVisible = true, - className + className, + ...props }: ChatbotProps) => { // Configure docked mode React.useEffect(() => { @@ -49,6 +50,7 @@ export const Chatbot: React.FunctionComponent = ({ variants={motionChatbot} initial="hidden" animate={isVisible ? 'visible' : 'hidden'} + {...props} > {isVisible ? children : undefined} diff --git a/packages/module/src/ChatbotToggle/ChatbotToggle.tsx b/packages/module/src/ChatbotToggle/ChatbotToggle.tsx index 6a9d76b4..f7692c91 100644 --- a/packages/module/src/ChatbotToggle/ChatbotToggle.tsx +++ b/packages/module/src/ChatbotToggle/ChatbotToggle.tsx @@ -1,15 +1,10 @@ // ============================================================================ // Chatbot Toggle // ============================================================================ - import React from 'react'; - -// Import PatternFly components import { Button, ButtonProps, Tooltip, TooltipProps, Icon } from '@patternfly/react-core'; import AngleDownIcon from '@patternfly/react-icons/dist/esm/icons/angle-down-icon'; -// Import Chatbot components - export interface ChatbotToggleProps extends ButtonProps { /** Contents of the tooltip applied to the toggle button */ toolTipLabel?: React.ReactNode; @@ -23,6 +18,8 @@ export interface ChatbotToggleProps extends ButtonProps { toggleButtonLabel?: string; /** An image displayed in the chatbot toggle when it is closed */ closedToggleIcon?: () => JSX.Element; + /** Ref applied to toggle */ + innerRef?: React.Ref; } const ChatIcon = () => ( @@ -44,13 +41,14 @@ const ChatIcon = () => ( ); -export const ChatbotToggle: React.FunctionComponent = ({ +const ChatbotToggleBase: React.FunctionComponent = ({ toolTipLabel, isChatbotVisible, onToggleChatbot, tooltipProps, toggleButtonLabel, closedToggleIcon: ClosedToggleIcon, + innerRef, ...props }: ChatbotToggleProps) => { // Configure icon @@ -66,6 +64,7 @@ export const ChatbotToggle: React.FunctionComponent = ({ onClick={onToggleChatbot} aria-expanded={isChatbotVisible} icon={{icon}} + ref={innerRef} {...props} > {/* Notification dot placeholder */} @@ -74,4 +73,8 @@ export const ChatbotToggle: React.FunctionComponent = ({ ); }; +const ChatbotToggle = React.forwardRef((props: ChatbotToggleProps, ref: React.Ref) => ( + +)); + export default ChatbotToggle; diff --git a/packages/module/src/MessageBox/MessageBox.tsx b/packages/module/src/MessageBox/MessageBox.tsx index f16555a0..ed8e2b4e 100644 --- a/packages/module/src/MessageBox/MessageBox.tsx +++ b/packages/module/src/MessageBox/MessageBox.tsx @@ -13,18 +13,27 @@ export interface MessageBoxProps extends React.HTMLProps { children: React.ReactNode; /** Custom classname for the MessageBox component */ className?: string; + /** Ref applied to message box */ + innerRef?: React.Ref; } -const MessageBox: React.FunctionComponent = ({ +const MessageBoxBase: React.FunctionComponent = ({ announcement, ariaLabel = 'Scrollable message log', children, + innerRef, className }: MessageBoxProps) => { const [atTop, setAtTop] = React.useState(false); const [atBottom, setAtBottom] = React.useState(true); const [isOverflowing, setIsOverflowing] = React.useState(false); - const messageBoxRef = React.useRef(null); + const defaultRef = React.useRef(null); + let messageBoxRef; + if (innerRef) { + messageBoxRef = innerRef; + } else { + messageBoxRef = defaultRef; + } // Configure handlers const handleScroll = React.useCallback(() => { @@ -83,7 +92,7 @@ const MessageBox: React.FunctionComponent = ({ tabIndex={0} aria-label={ariaLabel} className={`pf-chatbot__messagebox ${className ?? ''}`} - ref={messageBoxRef} + ref={innerRef ?? messageBoxRef} > {children}
@@ -95,4 +104,8 @@ const MessageBox: React.FunctionComponent = ({ ); }; +export const MessageBox = React.forwardRef((props: MessageBoxProps, ref: React.Ref) => ( + +)); + export default MessageBox; From 255b1ebb547630e00e1221693f5df36ce72275f0 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Tue, 5 Nov 2024 15:41:58 -0500 Subject: [PATCH 02/11] Address Eric's feedback --- .../examples/demos/Chatbot.tsx | 13 ++++++++--- .../examples/demos/EmbeddedChatbot.tsx | 4 ++-- packages/module/src/Chatbot/Chatbot.scss | 11 +++++++++ packages/module/src/Chatbot/Chatbot.tsx | 23 +++++++++++++++++-- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx index c9f3cfea..415cdac1 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx @@ -176,6 +176,7 @@ export const ChatbotDemo: React.FunctionComponent = () => { const [announcement, setAnnouncement] = React.useState(); const scrollToBottomRef = React.useRef(null); const toggleRef = React.useRef(null); + const chatbotRef = React.useRef(null); // Autu-scrolls to the latest message React.useEffect(() => { @@ -302,8 +303,14 @@ export const ChatbotDemo: React.FunctionComponent = () => { const handleSkipToContent = (e) => { e.preventDefault(); - if (toggleRef.current) { - toggleRef.current.focus(); + if (displayMode === ChatbotDisplayMode.default) { + if (toggleRef.current) { + toggleRef.current.focus(); + } + } else { + if (chatbotRef.current) { + chatbotRef.current.focus(); + } } }; @@ -319,7 +326,7 @@ export const ChatbotDemo: React.FunctionComponent = () => { id="chatbot-toggle" ref={toggleRef} /> - + { diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/EmbeddedChatbot.tsx b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/EmbeddedChatbot.tsx index 048c03b0..c1f6114b 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/EmbeddedChatbot.tsx +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/EmbeddedChatbot.tsx @@ -337,7 +337,7 @@ export const EmbeddedChatbotDemo: React.FunctionComponent = () => { return ( - + { @@ -390,7 +390,7 @@ export const EmbeddedChatbotDemo: React.FunctionComponent = () => { {/* Update the announcement prop on MessageBox whenever a new message is sent so that users of assistive devices receive sufficient context */} - + ; } export enum ChatbotDisplayMode { @@ -22,11 +24,12 @@ export enum ChatbotDisplayMode { fullscreen = 'fullscreen' } -export const Chatbot: React.FunctionComponent = ({ +const ChatbotBase: React.FunctionComponent = ({ children, displayMode = ChatbotDisplayMode.default, isVisible = true, className, + innerRef, ...props }: ChatbotProps) => { // Configure docked mode @@ -52,9 +55,25 @@ export const Chatbot: React.FunctionComponent = ({ animate={isVisible ? 'visible' : 'hidden'} {...props} > - {isVisible ? children : undefined} + {/* Ref is intended for use with skip to chatbot links, etc. */} + {/* Motion.div does not accept refs */} + {isVisible ? ( +
+ {children} +
+ ) : undefined} ); }; +const Chatbot = React.forwardRef((props: ChatbotProps, ref: React.Ref) => ( + +)); + export default Chatbot; From 5af69cc1912b9b8beb3c81c3aa6c899db6d7c263 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Wed, 6 Nov 2024 11:01:26 -0500 Subject: [PATCH 03/11] Address additional feedback --- .../virtual-assistant/examples/demos/Chatbot.tsx | 5 ++++- packages/module/src/Chatbot/Chatbot.tsx | 7 +++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx index 415cdac1..04b76410 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx @@ -304,9 +304,12 @@ export const ChatbotDemo: React.FunctionComponent = () => { const handleSkipToContent = (e) => { e.preventDefault(); if (displayMode === ChatbotDisplayMode.default) { - if (toggleRef.current) { + if (!chatbotVisible && toggleRef.current) { toggleRef.current.focus(); } + if (chatbotVisible && chatbotRef.current) { + chatbotRef.current.focus(); + } } else { if (chatbotRef.current) { chatbotRef.current.focus(); diff --git a/packages/module/src/Chatbot/Chatbot.tsx b/packages/module/src/Chatbot/Chatbot.tsx index 8dee3ffd..8c94509c 100644 --- a/packages/module/src/Chatbot/Chatbot.tsx +++ b/packages/module/src/Chatbot/Chatbot.tsx @@ -58,15 +58,14 @@ const ChatbotBase: React.FunctionComponent = ({ {/* Ref is intended for use with skip to chatbot links, etc. */} {/* Motion.div does not accept refs */} {isVisible ? ( -
{children} -
+ ) : undefined} ); From d5da90dad51f4d778a12afebade456658709da40 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Thu, 7 Nov 2024 17:07:35 -0500 Subject: [PATCH 04/11] Update packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md Co-authored-by: Erin Donehoo <105813956+edonehoo@users.noreply.github.com> --- .../extensions/virtual-assistant/examples/demos/Chatbot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md index 957fdde1..b4c5bf20 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md @@ -77,7 +77,7 @@ This demo displays a basic chatbot, which includes: 6. A [``](/patternfly-ai/chatbot/chatbot-conversation-history) toggled open and closed by the ` in the ``. -7. A skip to chatbot link, made with a [PatternFly 6 Skip to Content](/components/skip-to-content) +7. A "skip to chatbot" button that allows you to skip to the end of the chatbot content via the [PatternFly skip to content component](/components/skip-to-content). To display this button you must tab into the main window. ```js file="./Chatbot.tsx" isFullscreen From 1924bdefe419512a651d366d2c0a7c3ca2dd5df7 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Thu, 7 Nov 2024 17:07:50 -0500 Subject: [PATCH 05/11] Update packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md Co-authored-by: Erin Donehoo <105813956+edonehoo@users.noreply.github.com> --- .../extensions/virtual-assistant/examples/demos/Chatbot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md index b4c5bf20..ee4ab95b 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md @@ -87,7 +87,7 @@ This demo displays a basic chatbot, which includes: This demo displays an embedded chatbot. Embedded chatbots are meant to be placed within a page in your product. This demo includes: -1. A [PatternFly page](/components/page) with a sidebar, skip to chatbot link, and masthead +1. A [PatternFly page](/components/page) with a sidebar, "skip to chatbot" button, and masthead. To display the "skip to chatbot" button you must tab into the main window. 2. A [``](/patternfly-ai/chatbot/chatbot-container) container. 3. A [``](/patternfly-ai/chatbot/chatbot-header) with all built sub-components laid out, including a `` 4. [`` and ``](/patternfly-ai/chatbot/chatbot-container#content-and-message-box) with: From 2c2e7e670ea5f45c2f2125450c54697f1fda31f2 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Fri, 8 Nov 2024 17:52:00 -0500 Subject: [PATCH 06/11] chore(SkipToContent): Add direct example --- .../examples/Chatbot/Chatbot.md | 9 +++++ .../examples/Chatbot/SkipToContent.tsx | 40 +++++++++++++++++++ .../examples/demos/Chatbot.md | 2 +- packages/module/src/Chatbot/Chatbot.scss | 4 ++ 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/SkipToContent.tsx diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md index 10a05a0d..974b5efb 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md @@ -25,6 +25,7 @@ import ChatbotContent from '@patternfly/virtual-assistant/dist/dynamic/ChatbotCo import ChatbotWelcomePrompt from '@patternfly/virtual-assistant/dist/dynamic/ChatbotWelcomePrompt'; import MessageBox from '@patternfly/virtual-assistant/dist/dynamic/MessageBox'; import Message from '@patternfly/virtual-assistant/dist/dynamic/Message'; +import ChatbotToggle from '@patternfly/virtual-assistant/dist/dynamic/ChatbotToggle'; ### Container @@ -71,3 +72,11 @@ To provide users with a more specific direction, you can also include optional w ```js file="./ChatbotWelcomePrompt.tsx" ``` + +### Skip to content + +To provide page context, we recommend using a "skip to chatbot" button. This allows you to skip past other content on the page, directly to the chatbot content. The [PatternFly skip to content component](/components/skip-to-content) can be used for this purpose. To display this button, you must tab into the main window. We recommend putting focus on the toggle if the chatbot is closed, and the chatbot when it is open. + +```js file="./SkipToContent.tsx" isFullscreen + +``` diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/SkipToContent.tsx b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/SkipToContent.tsx new file mode 100644 index 00000000..e3fbefd9 --- /dev/null +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/SkipToContent.tsx @@ -0,0 +1,40 @@ +import React from 'react'; + +import { SkipToContent } from '@patternfly/react-core'; +import ChatbotToggle from '@patternfly/virtual-assistant/dist/dynamic/ChatbotToggle'; +import Chatbot, { ChatbotDisplayMode } from '@patternfly/virtual-assistant/dist/dynamic/Chatbot'; + +export const ChatbotDemo: React.FunctionComponent = () => { + const [chatbotVisible, setChatbotVisible] = React.useState(true); + const toggleRef = React.useRef(null); + const chatbotRef = React.useRef(null); + const displayMode = ChatbotDisplayMode.default; + + const handleSkipToContent = (e) => { + e.preventDefault(); + if (!chatbotVisible && toggleRef.current) { + toggleRef.current.focus(); + } + if (chatbotVisible && chatbotRef.current) { + chatbotRef.current.focus(); + } + }; + + return ( + <> + + Skip to chatbot + + setChatbotVisible(!chatbotVisible)} + id="chatbot-toggle" + ref={toggleRef} + /> + +   + + + ); +}; diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md index ee4ab95b..2c27a48f 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.md @@ -77,7 +77,7 @@ This demo displays a basic chatbot, which includes: 6. A [``](/patternfly-ai/chatbot/chatbot-conversation-history) toggled open and closed by the ` in the ``. -7. A "skip to chatbot" button that allows you to skip to the end of the chatbot content via the [PatternFly skip to content component](/components/skip-to-content). To display this button you must tab into the main window. +7. A "skip to chatbot" button that allows you to skip to the chatbot content via the [PatternFly skip to content component](/components/skip-to-content). To display this button you must tab into the main window. ```js file="./Chatbot.tsx" isFullscreen diff --git a/packages/module/src/Chatbot/Chatbot.scss b/packages/module/src/Chatbot/Chatbot.scss index a275b2e7..8afce748 100644 --- a/packages/module/src/Chatbot/Chatbot.scss +++ b/packages/module/src/Chatbot/Chatbot.scss @@ -70,6 +70,10 @@ html.pf-chatbot-allow--docked { } .pf-chatbot-container { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; // Hide chatbot &--hidden { pointer-events: none; From cf5b0835d74a49475a400eb4370477dc5a9f46e3 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Sun, 10 Nov 2024 09:45:25 -0500 Subject: [PATCH 07/11] fix(Chatbot): Should retain focus if no drawer Drawer is causing extra problems, but this should allow focus on the chatbot if there is no drawer. --- packages/module/src/Chatbot/Chatbot.scss | 18 +++++++++++++----- .../src/ChatbotFooter/ChatbotFooter.scss | 1 + .../src/ChatbotHeader/ChatbotHeader.scss | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/module/src/Chatbot/Chatbot.scss b/packages/module/src/Chatbot/Chatbot.scss index 8afce748..6437e648 100644 --- a/packages/module/src/Chatbot/Chatbot.scss +++ b/packages/module/src/Chatbot/Chatbot.scss @@ -13,7 +13,6 @@ border-radius: var(--pf-t--global--border--radius--medium); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); font-size: var(--pf-t--chatbot--font-size); - overflow: hidden; z-index: var(--pf-t--global--z-index--md); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; @@ -65,17 +64,26 @@ html.pf-chatbot-allow--docked { box-shadow: none; } -.pf-chatbot-container--embedded { - min-height: 100%; -} - .pf-chatbot-container { height: 100%; width: 100%; display: flex; flex-direction: column; + border-radius: var(--pf-t--global--border--radius--medium); + overflow: hidden; + // Hide chatbot &--hidden { pointer-events: none; } } + +.pf-chatbot-container--embedded { + min-height: 100%; +} + +.pf-chatbot-container--docked, +.pf-chatbot-container--embedded, +.pf-chatbot-container--fullscreen { + border-radius: unset; +} diff --git a/packages/module/src/ChatbotFooter/ChatbotFooter.scss b/packages/module/src/ChatbotFooter/ChatbotFooter.scss index 15d97471..d8918c35 100644 --- a/packages/module/src/ChatbotFooter/ChatbotFooter.scss +++ b/packages/module/src/ChatbotFooter/ChatbotFooter.scss @@ -10,6 +10,7 @@ display: flex; flex-direction: column; row-gap: var(--pf-chatbot__footer--RowGap); + position: relative; // this is so focus ring on parent chatbot doesn't include footer } .pf-chatbot__footer-container { padding: 0 var(--pf-t--global--spacer--lg) var(--pf-t--global--spacer--lg) var(--pf-t--global--spacer--lg); diff --git a/packages/module/src/ChatbotHeader/ChatbotHeader.scss b/packages/module/src/ChatbotHeader/ChatbotHeader.scss index 8e76f8f9..095afbfd 100644 --- a/packages/module/src/ChatbotHeader/ChatbotHeader.scss +++ b/packages/module/src/ChatbotHeader/ChatbotHeader.scss @@ -8,7 +8,7 @@ display: grid; grid-template-columns: 1fr auto; gap: var(--pf-t--global--spacer--sm); - position: relative; + position: relative; // this is so focus ring on parent chatbot doesn't include header background-color: var(--pf-t--chatbot--background); justify-content: space-between; padding: var(--pf-t--global--spacer--lg); From 8ddec0998cd99420be0eece343a12e3746cf1a45 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Sun, 10 Nov 2024 09:51:49 -0500 Subject: [PATCH 08/11] fix(ChatbotConversationHistoryNav): Fix borders --- .../ChatbotConversationHistoryNav.scss | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/module/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss b/packages/module/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss index 80052d1c..fb23e770 100644 --- a/packages/module/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +++ b/packages/module/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss @@ -4,6 +4,7 @@ .pf-chatbot__history { .pf-chatbot__drawer-backdrop { position: absolute; + border-radius: var(--pf-t--global--border--radius--medium); } // Drawer input // ---------------------------------------------------------------------------- @@ -153,3 +154,13 @@ } } } + +.pf-chatbot--docked, +.pf-chatbot--embedded, +.pf-chatbot--fullscreen { + .pf-chatbot__history { + .pf-chatbot__drawer-backdrop { + border-radius: unset; + } + } +} From edbd202d213e8f9a14e1b7150d8bc66e8d251af4 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Sun, 10 Nov 2024 10:04:32 -0500 Subject: [PATCH 09/11] chore(docs): For fullscreen and embedded, change focus For fullscreen and embedded, put focus on first element in section instead --- .../examples/demos/Chatbot.tsx | 40 +++++++++++++------ .../examples/demos/EmbeddedChatbot.tsx | 14 +++++-- packages/module/src/Chatbot/Chatbot.tsx | 5 ++- .../src/ChatbotHeader/ChatbotHeaderMenu.tsx | 14 +++++-- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx index 04b76410..49856868 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/demos/Chatbot.tsx @@ -177,6 +177,7 @@ export const ChatbotDemo: React.FunctionComponent = () => { const scrollToBottomRef = React.useRef(null); const toggleRef = React.useRef(null); const chatbotRef = React.useRef(null); + const historyRef = React.useRef(null); // Autu-scrolls to the latest message React.useEffect(() => { @@ -303,18 +304,29 @@ export const ChatbotDemo: React.FunctionComponent = () => { const handleSkipToContent = (e) => { e.preventDefault(); - if (displayMode === ChatbotDisplayMode.default) { - if (!chatbotVisible && toggleRef.current) { - toggleRef.current.focus(); - } - if (chatbotVisible && chatbotRef.current) { - chatbotRef.current.focus(); - } - } else { - if (chatbotRef.current) { - chatbotRef.current.focus(); - } + /* eslint-disable indent */ + switch (displayMode) { + case ChatbotDisplayMode.default: + if (!chatbotVisible && toggleRef.current) { + toggleRef.current.focus(); + } + if (chatbotVisible && chatbotRef.current) { + chatbotRef.current.focus(); + } + break; + + case ChatbotDisplayMode.docked: + if (chatbotRef.current) { + chatbotRef.current.focus(); + } + break; + default: + if (historyRef.current) { + historyRef.current.focus(); + } + break; } + /* eslint-enable indent */ }; return ( @@ -360,7 +372,11 @@ export const ChatbotDemo: React.FunctionComponent = () => { <> - setIsDrawerOpen(!isDrawerOpen)} /> + setIsDrawerOpen(!isDrawerOpen)} + /> { const [isSidebarOpen, setIsSidebarOpen] = React.useState(false); const [announcement, setAnnouncement] = React.useState(); const scrollToBottomRef = React.useRef(null); - const chatbotRef = React.useRef(null); + const historyRef = React.useRef(null); const displayMode = ChatbotDisplayMode.embedded; // Autu-scrolls to the latest message @@ -325,7 +325,9 @@ export const EmbeddedChatbotDemo: React.FunctionComponent = () => { const skipToChatbot = (event: React.MouseEvent) => { event.preventDefault(); - chatbotRef.current?.focus(); + if (historyRef.current) { + historyRef.current.focus(); + } }; const skipToContent = ( @@ -337,7 +339,7 @@ export const EmbeddedChatbotDemo: React.FunctionComponent = () => { return ( - + { @@ -368,7 +370,11 @@ export const EmbeddedChatbotDemo: React.FunctionComponent = () => { <> - setIsDrawerOpen(!isDrawerOpen)} /> + setIsDrawerOpen(!isDrawerOpen)} + /> {horizontalLogo} diff --git a/packages/module/src/Chatbot/Chatbot.tsx b/packages/module/src/Chatbot/Chatbot.tsx index 8c94509c..ff4bd9a8 100644 --- a/packages/module/src/Chatbot/Chatbot.tsx +++ b/packages/module/src/Chatbot/Chatbot.tsx @@ -15,6 +15,8 @@ export interface ChatbotProps { className?: string; /** Ref applied to chatbot */ innerRef?: React.Ref; + /** Custom aria label applied to focusable container */ + ariaLabel?: string; } export enum ChatbotDisplayMode { @@ -30,6 +32,7 @@ const ChatbotBase: React.FunctionComponent = ({ isVisible = true, className, innerRef, + ariaLabel, ...props }: ChatbotProps) => { // Configure docked mode @@ -59,7 +62,7 @@ const ChatbotBase: React.FunctionComponent = ({ {/* Motion.div does not accept refs */} {isVisible ? (
; } -export const ChatbotHeaderMenu: React.FunctionComponent = ({ +const ChatbotHeaderMenuBase: React.FunctionComponent = ({ className, onMenuToggle, tooltipProps, - menuAriaLabel = 'Toggle menu' + menuAriaLabel = 'Toggle menu', + innerRef }: ChatbotHeaderMenuProps) => (
@@ -27,6 +30,7 @@ export const ChatbotHeaderMenu: React.FunctionComponent variant="plain" onClick={onMenuToggle} aria-label={menuAriaLabel} + ref={innerRef} icon={ @@ -37,4 +41,8 @@ export const ChatbotHeaderMenu: React.FunctionComponent
); -export default ChatbotHeaderMenu; +export const ChatbotHeaderMenu = React.forwardRef( + (props: ChatbotHeaderMenuProps, ref: React.Ref) => ( + + ) +); From 9d328fd11255c42b390afd32888477388bacc66f Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Mon, 11 Nov 2024 10:06:07 -0500 Subject: [PATCH 10/11] chore(docs): Update docs --- .../extensions/virtual-assistant/examples/Chatbot/Chatbot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md index 974b5efb..6e5d64e2 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md @@ -75,7 +75,7 @@ To provide users with a more specific direction, you can also include optional w ### Skip to content -To provide page context, we recommend using a "skip to chatbot" button. This allows you to skip past other content on the page, directly to the chatbot content. The [PatternFly skip to content component](/components/skip-to-content) can be used for this purpose. To display this button, you must tab into the main window. We recommend putting focus on the toggle if the chatbot is closed, and the chatbot when it is open. +To provide page context, we recommend using a "skip to chatbot" button. This allows you to skip past other content on the page, directly to the chatbot content. The [PatternFly skip to content component](/components/skip-to-content) can be used for this purpose. To display this button, you must tab into the main window. When using default or docked modes, we recommend putting focus on the toggle if the chatbot is closed, and the chatbot when it is open. For fullscreen and embedded, we recommend putting the focus on the first focusable item in the chatbot, such as a menu toggle. This can be seen in our more fully-featured demos for the [default, embedded, and fullscreen chatbot](patternfly-ai/chatbot/chatbot-container/react-demos/basic-chatbot) and the [embedded chatbot](/patternfly-ai/chatbot/chatbot-container/react-demos/embedded-chatbot). ```js file="./SkipToContent.tsx" isFullscreen From 42ed0257f01c79e14b1bf9d807c7e6e62b0f5773 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Mon, 11 Nov 2024 18:57:04 -0500 Subject: [PATCH 11/11] chore(docs): Address feedback Also fixing test with build error after rebase. --- .../examples/Chatbot/Chatbot.md | 5 ++++- .../chatbot-container/react/skip-to-content.png | Bin 0 -> 7385 bytes .../src/ResponseActions/ResponseActions.test.tsx | 10 +++++----- 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 packages/module/patternfly-docs/generated/patternfly-ai/chatbot/chatbot-container/react/skip-to-content.png diff --git a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md index 6e5d64e2..c73cb88f 100644 --- a/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md +++ b/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/Chatbot/Chatbot.md @@ -75,7 +75,10 @@ To provide users with a more specific direction, you can also include optional w ### Skip to content -To provide page context, we recommend using a "skip to chatbot" button. This allows you to skip past other content on the page, directly to the chatbot content. The [PatternFly skip to content component](/components/skip-to-content) can be used for this purpose. To display this button, you must tab into the main window. When using default or docked modes, we recommend putting focus on the toggle if the chatbot is closed, and the chatbot when it is open. For fullscreen and embedded, we recommend putting the focus on the first focusable item in the chatbot, such as a menu toggle. This can be seen in our more fully-featured demos for the [default, embedded, and fullscreen chatbot](patternfly-ai/chatbot/chatbot-container/react-demos/basic-chatbot) and the [embedded chatbot](/patternfly-ai/chatbot/chatbot-container/react-demos/embedded-chatbot). +To provide page context, we recommend using a "skip to chatbot" button. This allows you to skip past other content on the page, directly to the chatbot content, using a [PatternFly skip to content component](/components/skip-to-content). To display this button, you must tab into the main window. +
+
+When using default or docked modes, we recommend putting focus on the toggle if the chatbot is closed, and the chatbot when it is open. For fullscreen and embedded, we recommend putting the focus on the first focusable item in the chatbot, such as a menu toggle. This can be seen in our more fully-featured demos for the [default, embedded, and fullscreen chatbot](patternfly-ai/chatbot/chatbot-container/react-demos/basic-chatbot) and the [embedded chatbot](/patternfly-ai/chatbot/chatbot-container/react-demos/embedded-chatbot). ```js file="./SkipToContent.tsx" isFullscreen diff --git a/packages/module/patternfly-docs/generated/patternfly-ai/chatbot/chatbot-container/react/skip-to-content.png b/packages/module/patternfly-docs/generated/patternfly-ai/chatbot/chatbot-container/react/skip-to-content.png new file mode 100644 index 0000000000000000000000000000000000000000..1ebf516ecd0fda919d41cb981fdcd845443082a1 GIT binary patch literal 7385 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 literal 0 HcmV?d00001 diff --git a/packages/module/src/ResponseActions/ResponseActions.test.tsx b/packages/module/src/ResponseActions/ResponseActions.test.tsx index 74a1d432..85ef6b93 100644 --- a/packages/module/src/ResponseActions/ResponseActions.test.tsx +++ b/packages/module/src/ResponseActions/ResponseActions.test.tsx @@ -31,11 +31,11 @@ describe('ResponseActions', () => { it('should be able to change aria labels', () => { const actions = [ - { type: 'positive', ariaLabel: /Thumbs up/i }, - { type: 'negative', ariaLabel: /Thumbs down/i }, - { type: 'copy', ariaLabel: /Copy the message/i }, - { type: 'share', ariaLabel: /Share it with friends/i }, - { type: 'listen', ariaLabel: /Listen up/i } + { type: 'positive', ariaLabel: 'Thumbs up' }, + { type: 'negative', ariaLabel: 'Thumbs down' }, + { type: 'copy', ariaLabel: 'Copy the message' }, + { type: 'share', ariaLabel: 'Share it with friends' }, + { type: 'listen', ariaLabel: 'Listen up' } ]; actions.forEach(({ type, ariaLabel }) => { render();