import { useUserHasResponded } from 'domains/app/hooks' import { useConfig } from 'domains/config/hooks' import { useI18n } from 'domains/i18n/hooks' import { useVisibility } from 'domains/visibility/hooks' import { createFocusTrap, FocusTrap } from 'focus-trap' import { className } from 'lib/css' import { ComponentChildren } from 'preact' import { forwardRef, useEffect, useRef } from 'preact/compat' import Suggestions from 'ui/components/suggestions' import { useSeamlyAppContainerClassNames } from 'ui/hooks/component-helper-hooks' import { useWindowOpenButtonFocusing } from 'ui/hooks/focus-helper-hooks' import { useSeamlyLayoutMode } from 'ui/hooks/seamly-state-hooks' import { useGeneratedId } from 'ui/hooks/utility-hooks' const Chat = forwardRef< HTMLElement, { children: ComponentChildren; className?: string } >(({ children, className: givenClassName = '' }, forwardedRef) => { const focusTrap = useRef(null) const { closeChat, isOpen, isVisible } = useVisibility() const focusWindowOpenButton = useWindowOpenButtonFocusing() const { namespace, layoutMode } = useConfig() const { isInline } = useSeamlyLayoutMode() const appContainerClassNames = useSeamlyAppContainerClassNames() const chatSectionId = useGeneratedId() const headingId = useGeneratedId() const userHasResponded = useUserHasResponded() const { t } = useI18n() const defaultClassNames = [ 'chat', `chat--layout-${layoutMode}`, `namespace--${namespace}`, ] const classNames = [...defaultClassNames, givenClassName] if (typeof appContainerClassNames !== 'function') { classNames.push(...appContainerClassNames) } if (!isOpen && layoutMode !== 'app') { classNames.push('chat--collapsed') } if (userHasResponded) { classNames.push('chat--user-responded') } const onKeyDownHandler = (e) => { if ((e.code && e.code === 'Escape') || e.keyCode === 27) if (!isInline && isOpen) { closeChat() focusWindowOpenButton() } } useEffect(() => { if (isVisible && layoutMode === 'window') { focusTrap.current = createFocusTrap(`#${chatSectionId}`, { // We set the initialFocus to false, as the `WindowOpenButton` takes care of that initialFocus: false, // Allow outside clicks to deactive the focus trap, so users can still navigate and use the site they are on // Users for which the focus trap is intended will (usually) not trigger this, and if they do, also intend this to happen clickOutsideDeactivates: true, }) focusTrap.current.activate() } return () => { if (focusTrap.current) { focusTrap.current.deactivate() } } }, [chatSectionId, isVisible, layoutMode]) return ( isVisible && (

{t('window.srModalLayoutLabel')}

{children}
{layoutMode === 'inline' && isOpen && }
) ) }) export default Chat