Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/search-ui-react.aisignpostprops.label.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## AISignpostProps.label property

Label displayed in the signpost button. Defaults to "AI-Generated".
Label displayed in the signpost button.

**Signature:**

Expand Down
2 changes: 1 addition & 1 deletion docs/search-ui-react.aisignpostprops.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ string

</td><td>

_(Optional)_ Label displayed in the signpost button. Defaults to "AI-Generated".
_(Optional)_ Label displayed in the signpost button.


</td></tr>
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yext/search-ui-react",
"version": "3.1.0",
"version": "3.1.1",
"description": "A library of React Components for powering Yext Search integrations",
"author": "watson@yext.com",
"license": "BSD-3-Clause",
Expand Down
19 changes: 11 additions & 8 deletions src/components/GenerativeDirectAnswer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { AISignpostIcon } from '../icons/AISignpostIcon';
import { CloseIcon } from '../icons/CloseIcon';
import { Markdown, MarkdownCssClasses } from './Markdown';
import { useId } from '../hooks/useId';
import { twMerge } from '../hooks/useComposedCssClasses';
import React, { useCallback, useMemo, useRef } from 'react';

/**
Expand Down Expand Up @@ -159,7 +160,7 @@ interface AnswerProps {
export interface AISignpostProps {
/** Icon displayed before the signpost label. Defaults to the SDK's AI signpost icon. */
icon?: React.JSX.Element,
/** Label displayed in the signpost button. Defaults to "AI-Generated". */
/** Label displayed in the signpost button. */
label?: string,
/** Header displayed in the signpost popover. Defaults to "AI-Generated Content". */
popoverHeader?: string,
Expand All @@ -181,6 +182,7 @@ function AISignpost({
const popoverId = useId('ai-signpost-popover');
const popoverHeaderId = useId('ai-signpost-popover-header');
const popoverDescriptionId = useId('ai-signpost-popover-description');
const ariaLabel = label ?? t('aiGeneratedAnswerSignpostLabel');
const handleSignpostClick = useCallback(() => {
setIsOpen(current => !current);
}, []);
Expand All @@ -189,24 +191,25 @@ function AISignpost({
}, []);

return (
<div className='relative mt-4 text-sm text-gray-700'>
<div className='relative text-sm text-gray-700'>
<button
type='button'
aria-expanded={isOpen}
aria-controls={popoverId}
className='inline-flex items-center gap-2 rounded-lg border border-slate-200 bg-slate-50 px-3 py-1.5 text-sm font-medium text-gray-700 transition-colors hover:bg-slate-100'
aria-label={ariaLabel}
className='inline-flex gap-1.5 items-center justify-center rounded-lg border border-slate-200 bg-slate-50 px-1.5 h-8 min-w-8 text-sm font-medium text-gray-700 transition-colors hover:bg-slate-100'
onClick={handleSignpostClick}
>
{icon ?? <AISignpostIcon className='h-4 w-4' />}
<span>{label ?? t('aiGeneratedAnswerSignpostLabel')}</span>
{label && <span>{label}</span>}
</button>
{isOpen && (
<div
id={popoverId}
role='dialog'
aria-labelledby={popoverHeaderId}
aria-describedby={popoverDescriptionId}
className='absolute left-0 top-full z-10 mt-2 w-80 max-w-full rounded-lg border border-gray-200 bg-white shadow-lg'
className='absolute left-0 top-full z-10 mt-2 w-80 rounded-lg border border-gray-200 bg-white shadow-lg'
>
<div className='flex flex-col px-4 py-3 gap-3'>
<div className='flex items-center justify-between'>
Expand Down Expand Up @@ -259,10 +262,10 @@ function Answer(props: AnswerProps) {
}, [linkClickHandler]);

return <>
<div className={cssClasses.header}>
{answerHeader ?? t('aiGeneratedAnswer')}
<div className={twMerge(cssClasses.header, 'flex items-center gap-2')}>
<div>{answerHeader ?? t('aiGeneratedAnswer')}</div>
{!hideAISignpost && <AISignpost {...aiSignpostProps} />}
</div>
{!hideAISignpost && <AISignpost {...aiSignpostProps} />}
<Markdown
content={gdaResponse.directAnswer}
onLinkClick={handleMarkdownLinkClick}
Expand Down
2 changes: 1 addition & 1 deletion test-site/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions tests/components/GenerativeDirectAnswer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe('GenerativeDirectAnswer with sufficient citation fields', () => {
mockAnswersState(mockedState);
});

it('displays the default AI signpost below the answer header', () => {
it('displays the default AI signpost next to the answer header', () => {
render(<GenerativeDirectAnswer />);

const answerHeader = screen.getByText('AI Generated Answer');
Expand Down Expand Up @@ -161,7 +161,7 @@ describe('GenerativeDirectAnswer with sufficient citation fields', () => {
/>);

expect(screen.getByTestId('custom-ai-signpost-icon')).toBeTruthy();
await userEvent.click(screen.getByRole('button', { name: 'Custom Icon Custom Label' }));
await userEvent.click(screen.getByRole('button', { name: 'Custom Label' }));

expect(screen.getByRole('dialog', { name: 'Custom Header' })).toBeTruthy();
expect(screen.getByText('Custom Body')).toBeTruthy();
Expand Down
Loading