1.0.4 • Published 9 months ago

@searchstax-inc/searchstudio-ux-react v1.0.4

Weekly downloads
-
License
-
Repository
-
Last release
9 months ago

sitesearch-ux-react

Library to build Site Search page

changelog

changelog is documented at CHANGELOG.md

Installation

npm install following package npm install --save @searchstax-inc/searchstudio-ux-react

Add following code to <head>

<script type="text/javascript">
      var _msq = _msq || []; //declare object
      var analyticsBaseUrl = 'https://analytics-us-east.searchstax.co';
      (function () {
        var ms = document.createElement('script');
        ms.type = 'text/javascript';
        ms.src = 'https://static.searchstax.co/studio-js/v3/js/studio-analytics.js';
        var s = document.getElementsByTagName('script')[0];
        s.parentNode.insertBefore(ms, s);
      })();
    </script>

Usage

After importing SearchstaxWrapper component needs to wrap all other components:

<SearchstaxWrapper
        searchURL={config.searchURL}
        suggesterURL={config.suggesterURL}
        trackApiKey={config.trackApiKey}
        searchAuth={config.searchAuth}
        initialized={initialized}
        beforeSearch={beforeSearch}
        afterSearch={afterSearch}
        authType="basic"
        language="en"
      >
  // other components will go there

  </SearchstaxWrapper>

Initialization

Initialization object needs to be of type: ISearchstaxConfig

Initialization example

sampleConfig = {
    language: "en",
    searchURL: "",
    suggesterURL: "",
    trackApiKey: "",
    searchAuth: "",
    authType: "basic",
    router: {
      enabled: true,
      routeName: "searchstax",
      title: (result: ISearchObject) => {
        return "Search results for: " + result.query;
      },
      ignoredKeys: [],
    },
    hooks: {
      beforeSearch: function (props: ISearchObject) {
        const propsCopy = { ...props };
        return propsCopy;
      },
      afterSearch: function (results: ISearchstaxParsedResult[]) {
        const copy = [...results];
        return copy;
      },
    }
  };

Initial layout

Our base theme is designed with this layout in mind but it is optional as all widgets have id parameters and can be attached to any element.

<SearchstaxWrapper
        searchURL={sampleConfig.searchURL}
        suggesterURL={sampleConfig.suggesterURL}
        trackApiKey={sampleConfig.trackApiKey}
        searchAuth={sampleConfig.searchAuth}
        beforeSearch={sampleConfig.hooks.beforeSearch}
        afterSearch={sampleConfig.hooks.afterSearch}
        authType="basic"
        language="en"
      >
        <div className="searchstax-page-layout-container">
          <SearchstaxInputWidget
            afterAutosuggest={afterAutosuggest}
            beforeAutosuggest={beforeAutosuggest}
            inputTemplate={InputTemplate}
          ></SearchstaxInputWidget>

          <div className="search-details-container">
            <div id="search-feedback-container"></div>
            <div id="search-sorting-container"></div>
          </div>

          <div className="searchstax-page-layout-facet-result-container">
            <div className="searchstax-page-layout-facet-container">
              <div id="searchstax-facets-container"></div>
            </div>

            <div className="searchstax-page-layout-result-container">
              <div id="searchstax-external-promotions-layout-container"></div>
              <SearchstaxResultWidget
                afterLinkClick={afterLinkClick}
                noResultTemplate={noResultTemplate}
                resultsTemplate={resultsTemplate}
              ></SearchstaxResultWidget>
              <div id="searchstax-related-searches-container"></div>
              <div id="searchstax-pagination-container"></div>
            </div>
          </div>
        </div>
      </SearchstaxWrapper>

widgets

Following widgets are available:

Input Widget

Result Widget

Facets Widget

Pagination Widget

SearchFeedback Widget

RelatedSearches Widget

ExternalPromotions Widget

sorting Widget

Input Widget

example of input widget initialization with minimum options

<SearchstaxInputWidget
            afterAutosuggest={afterAutosuggest}
            beforeAutosuggest={beforeAutosuggest}
          ></SearchstaxInputWidget>

example of input widget initialization with template override

 function InputTemplate(
    suggestions: ISearchstaxSuggestion[],
    onMouseLeave: () => void,
    onMouseOver: (suggestion: ISearchstaxSuggestion) => void,
    onMouseClick: () => void
  ): React.ReactElement {
    return (
    <div className="searchstax-search-input-wrapper">
        <input
          type="text"
          id="searchstax-search-input"
          className="searchstax-search-input"
          placeholder="SEARCH FOR..."
          aria-label="search"
        />
        <div
          className={`searchstax-autosuggest-container ${
            suggestions.length === 0 ? "hidden" : ""
          }`}
          onMouseLeave={onMouseLeave}
        >
          {suggestions.map(function (suggestion) {
            return (
              <div
                className="searchstax-autosuggest-item"
                key={suggestion.term}
              >
                <div
                  className="searchstax-autosuggest-item-term-container"
                  dangerouslySetInnerHTML={{ __html: suggestion.term }}
                  onMouseOver={() => {
                    onMouseOver(suggestion);
                  }}
                  onClick={() => {
                    onMouseClick();
                  }}
                ></div>
              </div>
            );
          })}
        </div>

        <button
          className="searchstax-spinner-icon"
          id="searchstax-search-input-action-button"
          aria-label="search"
        ></button>
      </div>
    );
  }


<SearchstaxInputWidget
            afterAutosuggest={afterAutosuggest}
            beforeAutosuggest={beforeAutosuggest}
            inputTemplate={InputTemplate}
          ></SearchstaxInputWidget>

Result Widget

example of results widget initialization with minimum options

<SearchstaxResultWidget
                afterLinkClick={afterLinkClick}
                renderMethod={'pagination'}
              ></SearchstaxResultWidget>

example of results widget initialization with minimum options for infinite scroll behavior

<SearchstaxResultWidget
                afterLinkClick={afterLinkClick}
                renderMethod={'infiniteScroll'}
              ></SearchstaxResultWidget>

example of result widget initialization with template override

function noResultTemplate(searchTerm: string, metaData: ISearchstaxSearchMetadata | null, executeSearch: (term:string) => void): React.ReactElement {
    return (
      <div>
        <div className="searchstax-no-results">
          {" "}
          Showing <strong>no results</strong> for <strong>"{searchTerm}"</strong>
          <br />
          {metaData?.spellingSuggestion && (
            <span>
              &nbsp;Did you mean{" "}
              <a href="#" className="searchstax-suggestion-term" onClick={(e) => {
                          e.preventDefault();
                          executeSearch(metaData?.spellingSuggestion);
                        }}>
                {metaData?.spellingSuggestion}
              </a>
              ?
            </span>
          )}
        </div>
        <ul>
          <li>
            {" "}
            Try searching for search related terms or topics. We offer a wide variety of content to help you get the
            information you need.{" "}
          </li>
          <li>Lost? Click on the ‘X” in the Search Box to reset your search.</li>
        </ul>
      </div>
    );
  }

  function resultsTemplate(
    searchResults: ISearchstaxParsedResult[],
    resultClicked: (results: ISearchstaxParsedResult, event: any) => ISearchstaxParsedResult[]
  ): React.ReactElement {
    return (
     <>
        {searchResults && searchResults.length && (
          <div className="searchstax-search-results">
            {searchResults !== null &&
              searchResults.map(function (searchResult) {
                return (
                  <a href={searchResult.url ?? ''} key={searchResult.uniqueId} onClick={event => {
                    resultClicked(searchResult, event);
                  }} tabIndex={0} data-searchstax-unique-result-id={ searchResult.uniqueId} className="searchstax-result-item-link searchstax-result-item-link-wrapping">
                  <div
                    className={`searchstax-search-result ${
                      searchResult.thumbnail ? "has-thumbnail" : ""
                    }`}
                    key={searchResult.uniqueId}
                  >
                    {searchResult.promoted && (
                      <div className="searchstax-search-result-promoted"></div>
                    )}


                    {searchResult.ribbon && (
                      <div className="searchstax-search-result-ribbon">
                        {searchResult.ribbon}
                      </div>
                    )}

                    {searchResult.thumbnail && (
                      <img
                        src={searchResult.thumbnail}
                        className="searchstax-thumbnail"
                      />
                    )}

                    <div className="searchstax-search-result-title-container">
                      <span className="searchstax-search-result-title">
                        {searchResult.title}
                      </span>
                    </div>

                    {searchResult.paths && (
                      <p className="searchstax-search-result-common">
                        {searchResult.paths}
                      </p>
                    )}

                    {searchResult.description && (
                      <p className="searchstax-search-result-description searchstax-search-result-common">
                        {searchResult.description}
                      </p>
                    )}

                    {searchResult.unmappedFields.map(function (
                      unmappedField: any
                    ) {
                      return (
                        <div key={unmappedField.key}>
                          {unmappedField.isImage &&
                            typeof unmappedField.value === "string" && (
                              <div className="searchstax-search-result-image-container">
                                <img
                                  src={unmappedField.value}
                                  className="searchstax-result-image"
                                />
                              </div>
                            )}

                          {!unmappedField.isImage && (
                            <div>
                              <p className="searchstax-search-result-common">
                                {unmappedField.value}
                              </p>
                            </div>
                          )}
                        </div>
                      );
                    })}
                  </div>
                  </a>
                );
              })}
          </div>
        )}
      </>
    );
  }


<SearchstaxResultWidget
                afterLinkClick={afterLinkClick}
                noResultTemplate={noResultTemplate}
                resultsTemplate={resultsTemplate}
              ></SearchstaxResultWidget>

Pagination Widget

example of pagination widget initialization with minimum options

<SearchstaxPaginationWidget></SearchstaxPaginationWidget>

example of pagination widget initialization with various options

function paginationTemplate(
    paginationData: IPaginationData | null,
    nextPage: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void,
    previousPage: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void
  ) {
    return (
     <>
        {paginationData && paginationData?.totalResults !== 0 && (
          <div className="searchstax-pagination-container">
            <div className="searchstax-pagination-content">
              <a
                className="searchstax-pagination-previous"
                style={
                  paginationData?.isFirstPage ? { pointerEvents: "none" } : {}
                }
                onClick={(e) => {
                  previousPage(e);
                }}
                tabIndex={0}
                id="searchstax-pagination-previous"
              >
                {" "}
                &lt; Previous{" "}
              </a>
              <div className="searchstax-pagination-details">
                {" "}
                {paginationData?.startResultIndex} -{" "}
                {paginationData?.endResultIndex} of{" "}
                {paginationData?.totalResults}
              </div>
              <a
                className="searchstax-pagination-next"
                style={
                  paginationData?.isLastPage ? { pointerEvents: "none" } : {}
                }
                onClick={(e) => {
                  nextPage(e);
                }}
                tabIndex={0}
                id="searchstax-pagination-next"
              >
                Next &gt;
              </a>
            </div>
          </div>
        )}
      </>
    );
  }

  <SearchstaxPaginationWidget paginationTemplate={paginationTemplate}></SearchstaxPaginationWidget>

example of pagination widget for infinite scroll

    function infiniteScrollTemplate(
    paginationData: IPaginationData | null,
    nextPage: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void
  ) {
    return (
      <>
        {paginationData &&
          paginationData.isInfiniteScroll &&
          paginationData?.totalResults !== 0 &&
          !paginationData?.isLastPage && (
            <div className="searchstax-pagination-container">
              <a
                className="searchstax-pagination-load-more"
                onClick={(e) => {
                  nextPage(e);
                }}
                onKeyDown={(e) => {
                  if(e.key === 'Enter' || e.key === ' ') {
                    nextPage(e as any);
                  }
                }}
              >
                Show More &gt;
              </a>
            </div>
          )}
      </>
    );
  }

  <SearchstaxPaginationWidget infiniteScrollTemplate={infiniteScrollTemplate}></SearchstaxPaginationWidget>

Facets Widget

example of facets widget initialization with minimum options

<SearchstaxFacetsWidget
                facetingType="and"
                itemsPerPageDesktop={2}
                itemsPerPageMobile={3}
                specificFacets={undefined}
              ></SearchstaxFacetsWidget>

example of facets widget initialization with template overrides

function facetsTemplateDesktop(
    facetsTemplateDataDesktop: IFacetsTemplateData | null,
    facetContainers: {
      [key: string]: React.LegacyRef<HTMLDivElement> | undefined;
    },
    isNotDeactivated: (name: string) => boolean,
    toggleFacetGroup: (name: string) => void,
    selectFacet: (
      index: string,
      event: React.MouseEvent<HTMLDivElement, MouseEvent>,
      data: IFacetValueData,
      isInput: boolean
    ) => void,
    isChecked: (facetValue: IFacetValueData) => boolean | undefined,
    showMoreLessDesktop: (
      e: React.MouseEvent<HTMLDivElement, MouseEvent>,
      data: IFacetData
    ) => void
  ) {
    return (
      <div className="searchstax-facets-container-desktop">
        {facetsTemplateDataDesktop?.facets.map((facet) => {
          return (
            <div
              className={`searchstax-facet-container ${
                isNotDeactivated(facet.name) ? "active" : ""
              }`}
              key={facet.name + "desktop"}
            >
              <div>
                <div
                  className="searchstax-facet-title-container"
                  onClick={() => {
                    toggleFacetGroup(facet.name);
                  }}
                >
                  <div className="searchstax-facet-title"> {facet.label}</div>
                  <div className="searchstax-facet-title-arrow active"></div>
                </div>
                <div className="searchstax-facet-values-container">
                  {facet.values.map(
                    //@ts-ignore
                    (facetValue: IFacetValueData, key) => {
                      facetContainers[key + facet.name] = createRef();
                      return (
                        <div
                          key={facetValue.value + facetValue.parentName}
                          className={`searchstax-facet-value-container ${
                            facetValue.disabled
                              ? "searchstax-facet-value-disabled"
                              : ""
                          }`}
                          ref={facetContainers[key + facet.name]}
                        >
                          <div className={
                                    "searchstax-facet-input" +
                                    " desktop-" +
                                    key +
                                    facet.name
                                  }>
                            <input
                              type="checkbox"
                              className="searchstax-facet-input-checkbox"
                              checked={isChecked(facetValue)}
                              readOnly={true}
                              aria-label={facetValue.value + ' ' + facetValue.count}
                              disabled={facetValue.disabled}
                              onClick={(e) => {
                                selectFacet(
                                  key + facet.name,
                                  e,
                                  facetValue,
                                  true
                                );
                              }}
                            />
                          </div>
                          <div
                            className="searchstax-facet-value-label"
                            onClick={(e) => {
                              selectFacet(
                                key + facet.name,
                                e,
                                facetValue,
                                false
                              );
                            }}
                          >
                            {facetValue.value}
                          </div>
                          <div
                            className="searchstax-facet-value-count"
                            onClick={(e) => {
                              selectFacet(
                                key + facet.name,
                                e,
                                facetValue,
                                false
                              );
                            }}
                          >
                            ({facetValue.count})
                          </div>
                        </div>
                      );
                    }
                  )}

                  {facet.hasMoreFacets && (
                    <div className="searchstax-facet-show-more-container">
                      <div
                        className="searchstax-facet-show-more-container"
                        onClick={(e) => {
                          showMoreLessDesktop(e, facet);
                        }}
                      >
                        {facet.showingAllFacets && (
                          <div className="searchstax-facet-show-less-button searchstax-facet-show-button">
                            less
                          </div>
                        )}
                        {!facet.showingAllFacets && (
                          <div className="searchstax-facet-show-more-button  searchstax-facet-show-button">
                            more
                          </div>
                        )}
                      </div>
                    </div>
                  )}
                </div>
              </div>
            </div>
          );
        })}
      </div>
    );
  }

  function facetsTemplateMobile(
    facetsTemplateDataMobile: IFacetsTemplateData | null,
    selectedFacetsCheckboxes: IFacetValue[],
    facetContainers: {
      [key: string]: React.LegacyRef<HTMLDivElement> | undefined;
    },
    isNotDeactivated: (name: string) => boolean,
    toggleFacetGroup: (name: string) => void,
    selectFacet: (
      index: string,
      event: React.MouseEvent<HTMLDivElement, MouseEvent>,
      data: IFacetValueData,
      isInput: boolean
    ) => void,
    isChecked: (facetValue: IFacetValueData) => boolean | undefined,
    unselectFacet: (facet: IFacetValue) => void,
    showMoreLessMobile: (
      e: React.MouseEvent<HTMLDivElement, MouseEvent>,
      data: IFacetData
    ) => void,
    openOverlay: () => void,
    closeOverlay: () => void,
    unselectAll: () => void
  ) {
    return facetsTemplateDataMobile ? (
      <div className="searchstax-facets-container-mobile">
        <div className="searchstax-facets-pills-container">
          <div
            className="searchstax-facets-pill searchstax-facets-pill-filter-by"
            onClick={() => {
              openOverlay();
            }}
          >
            <div className="searchstax-facets-pill-label">Filter By</div>
          </div>
          <div className="searchstax-facets-pills-selected">
            {selectedFacetsCheckboxes.map((facet) => {
              return (
                <div
                  className="searchstax-facets-pill searchstax-facets-pill-facets"
                  key={facet.value}
                  onClick={() => {
                    unselectFacet(facet);
                  }}
                >
                  <div className="searchstax-facets-pill-label">
                    {facet.value} ({facet.count})
                  </div>
                  <div className="searchstax-facets-pill-icon-close"></div>
                </div>
              );
            })}
            {selectedFacetsCheckboxes.length !== 0 && (
              <div
                className="searchstax-facets-pill searchstax-clear-filters searchstax-facets-pill-clear-all"
                onClick={() => {
                  unselectAll();
                }}
              >
                <div className="searchstax-facets-pill-label">
                  Clear Filters
                </div>
              </div>
            )}
          </div>
          <div
            className={`searchstax-facets-mobile-overlay ${
              //@ts-ignore
              facetsTemplateDataMobile.overlayOpened ? "searchstax-show" : ""
            }`}
          >
            <div className="searchstax-facets-mobile-overlay-header">
              <div className="searchstax-facets-mobile-overlay-header-title">
                Filter By
              </div>
              <div
                className="searchstax-search-close"
                onClick={() => {
                  closeOverlay();
                }}
              ></div>
            </div>
            <div className="searchstax-facets-container-mobile">
              {facetsTemplateDataMobile?.facets.map((facet) => {
                return (
                  <div
                    key={facet.name + "mobile"}
                    className={`searchstax-facet-container ${
                      isNotDeactivated(facet.name) ? `active` : ``
                    }`}
                  >
                    <div>
                      <div
                        className="searchstax-facet-title-container"
                        onClick={() => {
                          toggleFacetGroup(facet.name);
                        }}
                      >
                        <div className="searchstax-facet-title">
                          {" "}
                          {facet.label}{" "}
                        </div>
                        <div className="searchstax-facet-title-arrow active"></div>
                      </div>
                      <div className="searchstax-facet-values-container">
                        {facet.values.map(
                          //@ts-ignore
                          (facetValue: IFacetValueData, key) => {
                            facetContainers[key + facet.name] = createRef();

                            return (
                              <div
                                key={facetValue.value + facetValue.parentName}
                                className={`searchstax-facet-value-container ${
                                  facetValue.disabled
                                    ? `searchstax-facet-value-disabled`
                                    : ``
                                }`}
                                ref={facetContainers[key + facet.name]}
                              >
                                <div className={
                                    "searchstax-facet-input" +
                                    " mobile-" +
                                    key +
                                    facet.name
                                  }>
                                  <input
                                    type="checkbox"
                                    className="searchstax-facet-input-checkbox"
                                    checked={isChecked(facetValue)}
                                    readOnly={true}
                                    aria-label={facetValue.value + ' ' + facetValue.count}
                                    disabled={facetValue.disabled}
                                    onClick={(e) => {
                                      selectFacet(
                                        key + facet.name,
                                        e,
                                        facetValue,
                                        true
                                      );
                                    }}
                                  />
                                </div>
                                <div
                                  className="searchstax-facet-value-label"
                                  onClick={(e) => {
                                    selectFacet(
                                      key + facet.name,
                                      e,
                                      facetValue,
                                      false
                                    );
                                  }}
                                >
                                  {facetValue.value}
                                </div>
                                <div
                                  className="searchstax-facet-value-count"
                                  onClick={(e) => {
                                    selectFacet(
                                      key + facet.name,
                                      e,
                                      facetValue,
                                      false
                                    );
                                  }}
                                >
                                  ({facetValue.count})
                                </div>
                              </div>
                            );
                          }
                        )}

                        <div
                          className="searchstax-facet-show-more-container"
                          v-if="facet.hasMoreFacets"
                        >
                          <div
                            className="searchstax-facet-show-more-container"
                            onClick={(e) => {
                              showMoreLessMobile(e, facet);
                            }}
                          >
                            {facet.showingAllFacets && (
                              <div className="searchstax-facet-show-less-button searchstax-facet-show-button">
                                less
                              </div>
                            )}
                            {!facet.showingAllFacets && (
                              <div className="searchstax-facet-show-more-button  searchstax-facet-show-button">
                                more
                              </div>
                            )}
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>
            <button
              className="searchstax-facets-mobile-overlay-done"
              onClick={() => {
                closeOverlay();
              }}
            >
              Done
            </button>
          </div>
        </div>
      </div>
    ) : (<></>);
  }
<SearchstaxFacetsWidget
                facetingType="and"
                itemsPerPageDesktop={2}
                itemsPerPageMobile={3}
                specificFacets={undefined}
                facetsTemplateDesktop={facetsTemplateDesktop}
                facetsTemplateMobile={facetsTemplateMobile}
              ></SearchstaxFacetsWidget>

SearchFeedback Widget

example of search feedback widget initialization with minimum options

<SearchstaxOverviewWidget></SearchstaxOverviewWidget>

example of search feedback widget initialization with template overrides

function searchOverviewTemplate(
    searchFeedbackData: null | ISearchstaxSearchFeedbackData,
    onOriginalQueryClick: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void
  ) {
    return (
      <>
        {searchFeedbackData && searchFeedbackData?.searchExecuted && searchFeedbackData?.totalResults > 0 && (
          <>
            Showing{" "}
            <b>
              {searchFeedbackData.startResultIndex} - {searchFeedbackData.endResultIndex}
            </b>{" "}
            of
            <b> {searchFeedbackData.totalResults}</b> results
            {searchFeedbackData.searchTerm && (
              <span>
                &nbsp;for "<b>{searchFeedbackData.searchTerm}</b>"{" "}
              </span>
            )}
            <div className="searchstax-feedback-container-suggested">
              {searchFeedbackData.autoCorrectedQuery && (
                <div>
                  {" "}
                  Search instead for{" "}
                  <a
                    href="#"
                    onClick={(e) => {
                      onOriginalQueryClick(e);
                    }}
                    className="searchstax-feedback-original-query"
                  >
                    {searchFeedbackData.originalQuery}
                  </a>
                </div>
              )}
            </div>
          </>
        )}
      </>
    );
  }
  <SearchstaxOverviewWidget searchOverviewTemplate={searchOverviewTemplate}></SearchstaxOverviewWidget>

RelatedSearches widget

example of search feedback widget initialization with minimum options

<SearchstaxRelatedSearchesWidget
                relatedSearchesURL={config.relatedSearchesURL}
                relatedSearchesAPIKey={config.relatedSearchesAPIKey}
              ></SearchstaxRelatedSearchesWidget>

example of search feedback widget initialization with template overrides

  function searchRelatedSearchesTemplate(
    relatedData: null | ISearchstaxRelatedSearchesData,
    executeSearch: (result: ISearchstaxRelatedSearchResult) => void
  ) {
    return (
      <>
        {relatedData && relatedData?.searchExecuted && relatedData?.hasRelatedSearches && (
          <div className="searchstax-related-searches-container" id="searchstax-related-searches-container">
            {" "}
            Related searches: <span id="searchstax-related-searches"></span>
            {relatedData.relatedSearches && (
              <span className="searchstax-related-search">
                {relatedData.relatedSearches.map((related) => (
                  <span
                    key={related.related_search}
                    onClick={() => {
                      executeSearch(related);
                    }}
                    className="searchstax-related-search searchstax-related-search-item"
                  >
                    {" "}
                    {related.related_search}
                    {!related.last && <span>,</span>}
                  </span>
                ))}
              </span>
            )}
          </div>
        )}
      </>
    );
  }
  <SearchstaxRelatedSearchesWidget
                relatedSearchesURL={config.relatedSearchesURL}
                relatedSearchesAPIKey={config.relatedSearchesAPIKey}
                searchRelatedSearchesTemplate={searchRelatedSearchesTemplate}
              ></SearchstaxRelatedSearchesWidget>

ExternalPromotions widget

example of search feedback widget initialization with minimum options

<SearchstaxExternalPromotionsWidget></SearchstaxExternalPromotionsWidget>

example of search feedback widget initialization with template overrides

  function searchExternalPromotionsTemplate(
    externalPromotionsData: null | ISearchstaxExternalPromotionsData,
    trackClick: (externalPromotion: IExternalPromotion, event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void
  ) {
    return (
      <>
        {externalPromotionsData &&
          externalPromotionsData?.searchExecuted &&
          externalPromotionsData?.hasExternalPromotions &&
          externalPromotionsData.externalPromotions.map((externalPromotion) => (
            <div className="searchstax-external-promotion searchstax-search-result" key={externalPromotion.id}>
              <div className="icon-elevated"></div>
              {externalPromotion.url && (
                <a
                  href={externalPromotion.url}
                  onClick={(event) => {
                    trackClick(externalPromotion, event);
                  }}
                  className="searchstax-result-item-link"
                ></a>
              )}
              <div className="searchstax-search-result-title-container">
                <span className="searchstax-search-result-title">{externalPromotion.name}</span>
              </div>
              {externalPromotion.description && (
                <p className="searchstax-search-result-description searchstax-search-result-common">
                  {" "}
                  {externalPromotion.description}{" "}
                </p>
              )}
              {externalPromotion.url && (
                <p className="searchstax-search-result-description searchstax-search-result-common">
                  {" "}
                  {externalPromotion.url}{" "}
                </p>
              )}
            </div>
          ))}
      </>
    );
  }
<SearchstaxExternalPromotionsWidget
                searchExternalPromotionsTemplate={searchExternalPromotionsTemplate}
              ></SearchstaxExternalPromotionsWidget>

Sorting Widget

example of sorting widget initialization with minimum options

<SearchstaxSortingWidget></SearchstaxSortingWidget>

example of sorting widget initialization with template override

 function searchSortingTemplate(
    sortingData: null | ISearchstaxSearchSortingData,
    orderChange: (value: string) => void,
    selectedSorting: string
  ) {
    return (
      <>
        {sortingData && sortingData?.searchExecuted && sortingData?.hasResultsOrExternalPromotions && (
          <div className="searchstax-sorting-container">
            <label className="searchstax-sorting-label" htmlFor="searchstax-search-order-select">
              Sort By
            </label>
            <select
              id="searchstax-search-order-select"
              className="searchstax-search-order-select"
              value={selectedSorting}
              onChange={(e) => {
                orderChange(e.target.value);
              }}
            >
              {sortingData.sortOptions.map(function (sortOption) {
                  return (
                    <option key={sortOption.key} value={sortOption.key}>
                      {sortOption.value}
                    </option>
                  );
                })}
            </select>
          </div>
        )}
      </>
    );
  }
  <SearchstaxSortingWidget searchSortingTemplate={searchSortingTemplate}></SearchstaxSortingWidget>

Template overrides

Templates use vue slots.

STYLING

scss styles can be imported from searchstudio-ux-js

 @import './../node_modules/@searchstax-inc/searchstudio-ux-js/dist/styles/scss/mainTheme.scss';

css can be taken from

./../node_modules/@searchstax-inc/searchstudio-ux-js/dist/styles/mainTheme.css
1.0.4

9 months ago

1.0.2

9 months ago

1.0.1

9 months ago

1.0.3

9 months ago

0.3.18

10 months ago

0.3.17

10 months ago

0.3.16

11 months ago

0.3.15

12 months ago

0.2.18

1 year ago

0.2.17

1 year ago

0.3.5

12 months ago

0.3.1

1 year ago

0.3.3

1 year ago

0.2.15

1 year ago

0.2.14

1 year ago

0.2.13

1 year ago

0.2.12

1 year ago

0.2.11

1 year ago

0.2.10

1 year ago

0.2.7

1 year ago

0.2.6

1 year ago

0.2.9

1 year ago

0.2.8

1 year ago

0.2.5

1 year ago

0.2.3

1 year ago

0.2.4

1 year ago

0.1.0

2 years ago

0.2.1

2 years ago

0.2.0

2 years ago

0.2.2

2 years ago

0.0.11

2 years ago

0.0.10

2 years ago

0.0.9

2 years ago

0.0.7

2 years ago

0.0.6

2 years ago

0.0.5

2 years ago

0.0.3

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago