diff --git a/packages/headless/doc-parser/use-cases/search.ts b/packages/headless/doc-parser/use-cases/search.ts index 8ca9a1cbcc4..36c8a7b491c 100644 --- a/packages/headless/doc-parser/use-cases/search.ts +++ b/packages/headless/doc-parser/use-cases/search.ts @@ -440,6 +440,32 @@ const controllers: ControllerConfiguration[] = [ ], }, }, + { + initializer: 'buildAutomaticFacetBuilder', + samplePaths: { + react_class: [ + 'packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.class.tsx', + 'packages/samples/headless-react/src/components/automatic-facet/automatic-facet.class.tsx', + ], + react_fn: [ + 'packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.fn.tsx', + 'packages/samples/headless-react/src/components/automatic-facet/automatic-facet.fn.tsx', + ], + }, + }, + { + initializer: 'buildAutomaticFacet', + samplePaths: { + react_fn: [ + 'packages/samples/headless-react/src/components/automatic-facet/automatic-facet.fn.tsx', + 'packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.fn.tsx', + ], + react_class: [ + 'packages/samples/headless-react/src/components/automatic-facet/automatic-facet.class.tsx', + 'packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.class.tsx', + ], + }, + }, ]; const actionLoaders: ActionLoaderConfiguration[] = [ diff --git a/packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.class.tsx b/packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.class.tsx new file mode 100644 index 00000000000..9e33ea75443 --- /dev/null +++ b/packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.class.tsx @@ -0,0 +1,54 @@ +import { + buildAutomaticFacetBuilder, + AutomaticFacetBuilderProps, + AutomaticFacetBuilderState, + AutomaticFacetBuilder as HeadlessAutomaticFacetBuilder, + Unsubscribe, +} from '@coveo/headless'; +import {Component, ContextType} from 'react'; +import {AppContext} from '../../context/engine'; +import {AutomaticFacet} from '../automatic-facet/automatic-facet.class'; + +export class AutomaticFacetBuilder extends Component< + AutomaticFacetBuilderProps, + AutomaticFacetBuilderState +> { + static contextType = AppContext; + context!: ContextType; + + private controller!: HeadlessAutomaticFacetBuilder; + private unsubscribe: Unsubscribe = () => {}; + + componentDidMount() { + this.controller = buildAutomaticFacetBuilder( + this.context.engine!, + this.props + ); + this.updateState(); + + this.unsubscribe = this.controller.subscribe(() => this.updateState()); + } + + componentWillUnmount() { + this.unsubscribe(); + } + + private updateState() { + this.setState(this.controller.state); + } + + render() { + if (!this.state) { + return null; + } + const automaticFacets = this.state.automaticFacets.map((facet) => { + return ( + + ); + }); + return automaticFacets; + } +} diff --git a/packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.fn.tsx b/packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.fn.tsx new file mode 100644 index 00000000000..c18e3a57406 --- /dev/null +++ b/packages/samples/headless-react/src/components/automatic-facet-builder/automatic-facet-builder.fn.tsx @@ -0,0 +1,37 @@ +import {AutomaticFacetBuilder as HeadlessAutomaticFacetBuilder} from '@coveo/headless'; +import {FunctionComponent, useEffect, useState} from 'react'; +import {AutomaticFacet as AutomaticFacetFn} from '../automatic-facet/automatic-facet.fn'; + +interface AutomaticFacetBuilderProps { + controller: HeadlessAutomaticFacetBuilder; +} + +export const AutomaticFacetBuilder: FunctionComponent< + AutomaticFacetBuilderProps +> = (props) => { + const {controller} = props; + const [state, setState] = useState(controller.state); + + useEffect(() => controller.subscribe(() => setState(controller.state)), []); + + const automaticFacets = state.automaticFacets.map((facet) => { + return ( + + ); + }); + return
{automaticFacets}
; +}; + +// usage + +/** + * ```tsx + * const props: AutomaticFacetBuilderProps = {desiredCount: 5} + * const controller = buildAutomaticFacetBuilder(engine, props); + * + * ; + * ``` + */ diff --git a/packages/samples/headless-react/src/components/automatic-facet/automatic-facet.class.tsx b/packages/samples/headless-react/src/components/automatic-facet/automatic-facet.class.tsx new file mode 100644 index 00000000000..77c205e19e9 --- /dev/null +++ b/packages/samples/headless-react/src/components/automatic-facet/automatic-facet.class.tsx @@ -0,0 +1,52 @@ +import { + AutomaticFacetState, + AutomaticFacet as HeadlessAutomaticFacet, + Unsubscribe, +} from '@coveo/headless'; +import {Component} from 'react'; + +interface AutomaticFacetProps { + controller: HeadlessAutomaticFacet; +} +export class AutomaticFacet extends Component< + AutomaticFacetProps, + AutomaticFacetState +> { + private controller!: HeadlessAutomaticFacet; + private unsubscribe: Unsubscribe = () => {}; + + componentDidMount() { + this.controller = this.props.controller; + this.updateState(); + + this.unsubscribe = this.controller.subscribe(() => this.updateState()); + } + + componentWillUnmount() { + this.unsubscribe(); + } + + private updateState() { + this.setState(this.controller.state); + } + + render() { + if (!this.state) { + return null; + } + return ( + + ); + } +} diff --git a/packages/samples/headless-react/src/components/automatic-facet/automatic-facet.fn.tsx b/packages/samples/headless-react/src/components/automatic-facet/automatic-facet.fn.tsx new file mode 100644 index 00000000000..504136a044d --- /dev/null +++ b/packages/samples/headless-react/src/components/automatic-facet/automatic-facet.fn.tsx @@ -0,0 +1,30 @@ +import {AutomaticFacet as HeadlessAutomaticFacet} from '@coveo/headless'; +import {FunctionComponent, useEffect, useState} from 'react'; + +interface AutomaticFacetProps { + controller: HeadlessAutomaticFacet; +} + +export const AutomaticFacet: FunctionComponent = ( + props +) => { + const {controller} = props; + const [state, setState] = useState(controller.state); + + useEffect(() => controller.subscribe(() => setState(controller.state)), []); + + return ( +
    + {state.values.map((value) => ( +
  • + controller.toggleSelect(value)} + /> + {value.value} ({value.numberOfResults} results) +
  • + ))} +
+ ); +}; diff --git a/packages/samples/headless-react/src/pages/SearchPage.tsx b/packages/samples/headless-react/src/pages/SearchPage.tsx index 704c1d2b14e..12106436097 100644 --- a/packages/samples/headless-react/src/pages/SearchPage.tsx +++ b/packages/samples/headless-react/src/pages/SearchPage.tsx @@ -77,10 +77,14 @@ import { RecentResultsList as HeadlessRecentResultsList, buildRecentResultsList, InstantResults as HeadlessInstantResults, + AutomaticFacetBuilder as HeadlessAutomaticFacetBuilder, buildInstantResults, + buildAutomaticFacetBuilder, } from '@coveo/headless'; import filesize from 'filesize'; import {Component} from 'react'; +import {AutomaticFacetBuilder} from '../components/automatic-facet-builder/automatic-facet-builder.class'; +import {AutomaticFacetBuilder as AutomaticFacetBuilderFn} from '../components/automatic-facet-builder/automatic-facet-builder.fn'; import {BreadcrumbManager} from '../components/breadcrumb-manager/breadcrumb-manager.class'; import {BreadcrumbManager as BreadcrumbManagerFn} from '../components/breadcrumb-manager/breadcrumb-manager.fn'; import {CategoryFacet} from '../components/category-facet/category-facet.class'; @@ -225,6 +229,7 @@ export class SearchPage extends Component { private readonly recentResultsList: HeadlessRecentResultsList; private readonly instantResults: HeadlessInstantResults; private readonly searchboxInstantResults: HeadlessSearchBox; + private readonly automaticFacetBuilder: HeadlessAutomaticFacetBuilder; private unsubscribeUrlManager!: Unsubscribe; @@ -273,6 +278,10 @@ export class SearchPage extends Component { this.facetManager = buildFacetManager(this.engine); + this.automaticFacetBuilder = buildAutomaticFacetBuilder(this.engine, { + desiredCount: 5, + }); + this.geographyFacet = buildCategoryFacet(this.engine, { options: { field: 'geographicalhierarchy', @@ -585,6 +594,7 @@ export class SearchPage extends Component {
+ +