Skip to content

Commit

Permalink
more UI improvements. also tested to ensure if a gda call return no a…
Browse files Browse the repository at this point in the history
…nswer, the previous gda result is not rendered
  • Loading branch information
anguyen-yext2 committed Jun 20, 2024
1 parent 75a965c commit 51eb59a
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 26 deletions.
11 changes: 11 additions & 0 deletions docs/search-ui-react.citationprops.citation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [CitationProps](./search-ui-react.citationprops.md) &gt; [citation](./search-ui-react.citationprops.citation.md)

## CitationProps.citation property

**Signature:**

```typescript
citation: string;
```
11 changes: 11 additions & 0 deletions docs/search-ui-react.citationprops.cssclasses.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [CitationProps](./search-ui-react.citationprops.md) &gt; [cssClasses](./search-ui-react.citationprops.cssclasses.md)

## CitationProps.cssClasses property

**Signature:**

```typescript
cssClasses: GenerativeDirectAnswerCssClasses;
```
22 changes: 22 additions & 0 deletions docs/search-ui-react.citationprops.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [CitationProps](./search-ui-react.citationprops.md)

## CitationProps interface

Props for citation card.

**Signature:**

```typescript
interface CitationProps
```

## Properties

| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [citation](./search-ui-react.citationprops.citation.md) | | string | |
| [cssClasses](./search-ui-react.citationprops.cssclasses.md) | | [GenerativeDirectAnswerCssClasses](./search-ui-react.generativedirectanswercssclasses.md) | |
| [searchResults](./search-ui-react.citationprops.searchresults.md) | | Result\[\] | |

11 changes: 11 additions & 0 deletions docs/search-ui-react.citationprops.searchresults.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [CitationProps](./search-ui-react.citationprops.md) &gt; [searchResults](./search-ui-react.citationprops.searchresults.md)

## CitationProps.searchResults property

**Signature:**

```typescript
searchResults: Result[];
```
4 changes: 2 additions & 2 deletions docs/search-ui-react.generativedirectanswer.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ Displays the AI generated answer of a generative direct answer.
**Signature:**

```typescript
declare function GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader }: GenerativeDirectAnswerProps): JSX.Element | null;
declare function GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader, CitationCard }: GenerativeDirectAnswerProps): JSX.Element | null;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| { customCssClasses, answerHeader, citationsHeader } | [GenerativeDirectAnswerProps](./search-ui-react.generativedirectanswerprops.md) | |
| { customCssClasses, answerHeader, citationsHeader, CitationCard } | [GenerativeDirectAnswerProps](./search-ui-react.generativedirectanswerprops.md) | |

**Returns:**

Expand Down
13 changes: 13 additions & 0 deletions docs/search-ui-react.generativedirectanswerprops.citationcard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [GenerativeDirectAnswerProps](./search-ui-react.generativedirectanswerprops.md) &gt; [CitationCard](./search-ui-react.generativedirectanswerprops.citationcard.md)

## GenerativeDirectAnswerProps.CitationCard property

The component for citation card

**Signature:**

```typescript
CitationCard?: (props: CitationProps) => JSX.Element | null;
```
1 change: 1 addition & 0 deletions docs/search-ui-react.generativedirectanswerprops.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface GenerativeDirectAnswerProps
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [answerHeader?](./search-ui-react.generativedirectanswerprops.answerheader.md) | | string \| JSX.Element | _(Optional)_ The header for the answer section of the generative direct answer. |
| [CitationCard?](./search-ui-react.generativedirectanswerprops.citationcard.md) | | (props: [CitationProps](./search-ui-react.citationprops.md)<!-- -->) =&gt; JSX.Element \| null | _(Optional)_ The component for citation card |
| [citationsHeader?](./search-ui-react.generativedirectanswerprops.citationsheader.md) | | string \| JSX.Element | _(Optional)_ The header for the citations section of the generative direct answer. |
| [customCssClasses?](./search-ui-react.generativedirectanswerprops.customcssclasses.md) | | [GenerativeDirectAnswerCssClasses](./search-ui-react.generativedirectanswercssclasses.md) | _(Optional)_ CSS classes for customizing the component styling. |

3 changes: 2 additions & 1 deletion docs/search-ui-react.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
| [Facets(props)](./search-ui-react.facets.md) | A component that displays all facets applicable to the current vertical search. |
| [FilterDivider({ className })](./search-ui-react.filterdivider.md) | A divider component used to separate NumericalFacets, HierarchicalFacets, StandardFacets, and StaticFilters. |
| [FilterSearch({ searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, afterDropdownInputFocus, sectioned, customCssClasses })](./search-ui-react.filtersearch.md) | A component which allows a user to search for filters associated with specific entities and fields. |
| [GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader })](./search-ui-react.generativedirectanswer.md) | Displays the AI generated answer of a generative direct answer. |
| [GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader, CitationCard })](./search-ui-react.generativedirectanswer.md) | Displays the AI generated answer of a generative direct answer. |
| [Geolocation\_2({ geolocationOptions, radius, label, GeolocationIcon, handleClick, customCssClasses, })](./search-ui-react.geolocation_2.md) | A React Component which collects location information to create a location filter and perform a new search. |
| [getSearchIntents(searchActions)](./search-ui-react.getsearchintents.md) | Get search intents of the current query stored in headless using autocomplete request. |
| [getUserLocation(geolocationOptions)](./search-ui-react.getuserlocation.md) | Retrieves user's location using navigator.geolocation API. |
Expand Down Expand Up @@ -63,6 +63,7 @@
| [ApplyFiltersButtonProps](./search-ui-react.applyfiltersbuttonprops.md) | Props for [ApplyFiltersButton()](./search-ui-react.applyfiltersbutton.md) |
| [AutocompleteResultCssClasses](./search-ui-react.autocompleteresultcssclasses.md) | The CSS class interface for the Autocomplete Result. |
| [CardProps](./search-ui-react.cardprops.md) | The props provided to every [CardComponent](./search-ui-react.cardcomponent.md)<!-- -->. |
| [CitationProps](./search-ui-react.citationprops.md) | Props for citation card. |
| [Coordinate](./search-ui-react.coordinate.md) | Coordinate use to represent the result's location on a map. |
| [CtaData](./search-ui-react.ctadata.md) | The shape of a StandardCard CTA field's data. |
| [DirectAnswerCssClasses](./search-ui-react.directanswercssclasses.md) | The CSS class interface for [DirectAnswer()](./search-ui-react.directanswer.md)<!-- -->. |
Expand Down
13 changes: 12 additions & 1 deletion etc/search-ui-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ export interface CardProps<T = DefaultRawDataType> {
result: Result<T>;
}

// @public
export interface CitationProps {
// (undocumented)
citation: string;
// (undocumented)
cssClasses: GenerativeDirectAnswerCssClasses;
// (undocumented)
searchResults: Result[];
}

// @public
export const ComponentsContentPath = "node_modules/@yext/search-ui-react/lib/**/*.{js,jsx}";

Expand Down Expand Up @@ -313,7 +323,7 @@ export interface FilterSearchProps {
export type FocusedItemData = Record<string, unknown>;

// @public
export function GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader }: GenerativeDirectAnswerProps): JSX.Element | null;
export function GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader, CitationCard }: GenerativeDirectAnswerProps): JSX.Element | null;

// @public
export interface GenerativeDirectAnswerCssClasses {
Expand All @@ -338,6 +348,7 @@ export interface GenerativeDirectAnswerCssClasses {
// @public
export interface GenerativeDirectAnswerProps {
answerHeader?: string | JSX.Element;
CitationCard?: (props: CitationProps) => JSX.Element | null;
citationsHeader?: string | JSX.Element;
customCssClasses?: GenerativeDirectAnswerCssClasses;
}
Expand Down
61 changes: 42 additions & 19 deletions src/components/GenerativeDirectAnswer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
GenerativeDirectAnswerResponse,
useSearchActions,
useSearchState,
SearchTypeEnum,
Result
} from '@yext/search-headless-react';
import { useComposedCssClasses } from '../hooks';
Expand Down Expand Up @@ -31,7 +32,7 @@ const builtInCssClasses: Readonly<GenerativeDirectAnswerCssClasses> = {
answerText: 'mt-4',
divider: 'border-b border-gray-200 w-full pb-6 mb-6',
citationsContainer: 'mt-4 flex overflow-x-auto gap-4',
citation: 'p-4 border border-gray-200 rounded-lg shadow-sm bg-slate-100 flex flex-col grow-0 shrink-0 basis-64 text-sm text-neutral',
citation: 'p-4 border border-gray-200 rounded-lg shadow-sm bg-slate-100 flex flex-col grow-0 shrink-0 basis-64 text-sm text-neutral overflow-x-auto',
citationTitle: 'font-bold',
citationSnippet: 'line-clamp-2 text-ellipsis break-words'
};
Expand All @@ -45,9 +46,11 @@ export interface GenerativeDirectAnswerProps {
/** CSS classes for customizing the component styling. */
customCssClasses?: GenerativeDirectAnswerCssClasses,
/** The header for the answer section of the generative direct answer. */
answerHeader?: string | JSX.Element
answerHeader?: string | JSX.Element,
/** The header for the citations section of the generative direct answer. */
citationsHeader?: string | JSX.Element
citationsHeader?: string | JSX.Element,
/** The component for citation card */
CitationCard?: (props: CitationProps) => JSX.Element | null
}

/**
Expand All @@ -61,20 +64,22 @@ export interface GenerativeDirectAnswerProps {
export function GenerativeDirectAnswer({
customCssClasses,
answerHeader,
citationsHeader
citationsHeader,
CitationCard
}: GenerativeDirectAnswerProps): JSX.Element | null {
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);

const isUniversal = useSearchState(state => state.meta.searchType) === SearchTypeEnum.Universal;
const universalResults = useSearchState(state => state.universal);
const verticalResults = useSearchState(state => state.vertical);

const searchResults: Result[] | undefined = React.useMemo(() => {
if (universalResults) {
if (isUniversal) {
return universalResults.verticals?.flatMap(v => v.results);
} else if (verticalResults) {
} else {
return verticalResults.results;
}
}, [universalResults, verticalResults]);
}, [isUniversal, universalResults, verticalResults]);

const searchActions = useSearchActions();
const gdaResponse = useSearchState(state => state.generativeDirectAnswer?.response);
Expand All @@ -89,21 +94,21 @@ export function GenerativeDirectAnswer({

if (!searchResults?.length || isLoading || !gdaResponse || gdaResponse.resultStatus !== 'SUCCESS') {
return null;
}
}

return (
<div className={cssClasses.container}>
<Answer gdaResponse={gdaResponse} cssClasses={cssClasses} answerHeader={answerHeader}/>
<div className={cssClasses.divider} />
<Citations gdaResponse={gdaResponse} cssClasses={cssClasses} citationsHeader={citationsHeader} searchResults={searchResults}/>
<Citations gdaResponse={gdaResponse} cssClasses={cssClasses} citationsHeader={citationsHeader} searchResults={searchResults} CitationCard={CitationCard}/>
</div>
);
}

interface AnswerProps extends GenerativeDirectAnswerProps {
interface AnswerProps {
gdaResponse: GenerativeDirectAnswerResponse,
cssClasses: GenerativeDirectAnswerCssClasses,
answerHeader?: string | JSX.Element,
answerHeader?: string | JSX.Element
}

/**
Expand All @@ -113,7 +118,7 @@ function Answer(props: AnswerProps) {
const {
gdaResponse,
cssClasses,
answerHeader,
answerHeader = 'AI Generated Answer'
} = props;
return <>
<div className={cssClasses.header}>
Expand All @@ -123,11 +128,12 @@ function Answer(props: AnswerProps) {
</>;
}

interface CitationsProps extends GenerativeDirectAnswerProps {
interface CitationsProps {
gdaResponse: GenerativeDirectAnswerResponse,
cssClasses: GenerativeDirectAnswerCssClasses,
citationsHeader?: string | JSX.Element,
searchResults: Result[]
searchResults: Result[],
CitationCard?: (props: CitationProps) => JSX.Element | null
}

/**
Expand All @@ -137,8 +143,9 @@ function Citations(props: CitationsProps) {
const {
gdaResponse,
cssClasses,
citationsHeader,
searchResults
citationsHeader = `Sources (${gdaResponse.citations.length})`,
searchResults,
CitationCard = Citation
} = props;
if (!gdaResponse.citations.length) {
return null;
Expand All @@ -149,18 +156,34 @@ function Citations(props: CitationsProps) {
</div>
<div className={cssClasses.citationsContainer}>
{gdaResponse.citations.map(
citation => Citation(searchResults, citation, cssClasses))}
citation => <CitationCard key={citation} searchResults={searchResults} citation={citation} cssClasses={cssClasses} />)}
</div>
</>;
}

function Citation(searchResults: Result[], citation: string, cssClasses: GenerativeDirectAnswerCssClasses) {
/**
* Props for citation card.
*
* @public
*/
export interface CitationProps {
searchResults: Result[],
citation: string,
cssClasses: GenerativeDirectAnswerCssClasses
}

function Citation(props: CitationProps) {
const {
searchResults,
citation,
cssClasses
} = props;
const rawResult: Result | undefined = searchResults.find(r => r.rawData.uid === citation);
if (!rawResult) {
return null;
}

return <div key={citation} className={cssClasses.citation}>
return <div className={cssClasses.citation}>
<div className={cssClasses.citationTitle}>{rawResult.rawData.name}</div>
<div className={cssClasses.citationSnippet}>{rawResult.rawData.description}</div>
</div>;
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,5 @@ export {
GenerativeDirectAnswer,
GenerativeDirectAnswerCssClasses,
GenerativeDirectAnswerProps,
CitationProps
} from './GenerativeDirectAnswer';
25 changes: 22 additions & 3 deletions test-site/src/pages/UniversalPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { provideHeadless, useSearchActions } from '@yext/search-headless-react';
import { provideHeadless, useSearchActions, Result } from '@yext/search-headless-react';
import {
DirectAnswer,
DropdownItem,
Expand All @@ -7,7 +7,8 @@ import {
SpellCheck,
UniversalResults,
VisualAutocompleteConfig,
GenerativeDirectAnswer
GenerativeDirectAnswer,
CitationProps
} from '@yext/search-ui-react';
import classNames from 'classnames';
import { useLayoutEffect } from 'react';
Expand Down Expand Up @@ -59,6 +60,24 @@ const customSearchBarCss = {
searchBarContainer: 'mb-3 text-emerald-800'
};

function CustomCitationCard(props: CitationProps): JSX.Element | null {
const {
searchResults,
citation,
cssClasses
} = props;
const rawResult: Result | undefined = searchResults.find((r: Result) => r.rawData.uid === citation);

if (!rawResult) {
return null;
}

return <div key={citation} className={cssClasses.citation}>
{typeof rawResult.rawData.id === 'string' && <div className={cssClasses.citationTitle}>{rawResult.rawData.id}</div>}
{typeof rawResult.rawData.type === 'string' && <div className={cssClasses.citationSnippet}>{rawResult.rawData.type}</div>}
</div>;
}

export default function UniversalPage(): JSX.Element {
const searchActions = useSearchActions();
useLayoutEffect(() => {
Expand All @@ -73,7 +92,7 @@ export default function UniversalPage(): JSX.Element {
customCssClasses={customSearchBarCss}
/>
<SpellCheck />
<GenerativeDirectAnswer answerHeader='AI Generated Answer' citationsHeader='Sources'/>
<GenerativeDirectAnswer answerHeader='A custom answer header' CitationCard={CustomCitationCard}/>
<DirectAnswer />
<ResultsCount />
<UniversalResults
Expand Down

0 comments on commit 51eb59a

Please sign in to comment.