{"version":3,"file":"index-6c485652.js","sources":["../../../../src/scripts/coveo/components/standalone-searchbox.tsx","../../../../src/scripts/coveo/modules/standalone-searchbox/index.tsx"],"sourcesContent":["import React, {\n  useEffect,\n  useState,\n  FunctionComponent,\n  useId,\n  useRef\n} from 'react';\nimport { rovingIndex } from 'roving-ux';\nimport { StandaloneSearchBox as HeadlessSearchBox } from '@coveo/headless';\nimport { SEARCH_KEYS } from '../controllers/search-keys';\nimport { secureStorage } from '../../helpers/global-storage';\nimport { isTablet } from '../../helpers/breakpoints';\n\ninterface SearchBoxProps {\n  controller: HeadlessSearchBox;\n  searchLabel: string;\n  searchPlaceholder: string;\n  submitLabel: string;\n  clearLabel: string;\n  viewResults: string;\n  maxSuggestions?: number;\n}\n\nexport const SEARCH_BOX_EVENTS = Object.freeze({\n  updateDidYouMean: 'searchbox:updateDidYouMean'\n});\n\nexport const StandaloneSearchBox: FunctionComponent<SearchBoxProps> = props => {\n  const id = useId();\n  const {\n    controller,\n    searchLabel,\n    searchPlaceholder,\n    clearLabel,\n    viewResults,\n    maxSuggestions\n  } = props;\n  const [state, setState] = useState(controller.state);\n  const [value, setValue] = useState(controller.state.value);\n  const [focus, setFocus] = useState(false);\n  const [open, setOpen] = useState(false);\n  const listRef = useRef<HTMLUListElement>(null);\n  const input = useRef<HTMLInputElement>(null);\n\n  const isEnterKey = (e: React.KeyboardEvent<HTMLDivElement>) =>\n    e.key === 'Enter';\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n    if (input.current === document.activeElement) {\n      if (isEnterKey(e)) {\n        e.preventDefault();\n        controller.updateText(value);\n        controller.submit();\n      }\n\n      if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n        e.preventDefault();\n        if (listRef.current) {\n          if (e.key === 'ArrowDown') {\n            const firstElement = listRef.current.querySelector('li');\n            if (firstElement) {\n              firstElement.querySelector('button')?.focus();\n              setFocus(true);\n              setOpen(true);\n            }\n          } else {\n            const lastElement = listRef.current.querySelector('li:last-child');\n            if (lastElement) {\n              (lastElement as HTMLLIElement).querySelector('button')?.focus();\n              setFocus(true);\n              setOpen(true);\n            }\n          }\n        }\n      }\n\n      if (e.key === 'Escape') {\n        e.preventDefault();\n        input.current?.blur();\n      }\n    } else {\n      if (e.key === 'Escape') {\n        e.preventDefault();\n        input.current?.focus();\n        setFocus(false);\n      }\n      if (\n        (e.key === 'ArrowDown' || e.key === 'ArrowUp') &&\n        e.currentTarget.querySelector('.field--search')\n      ) {\n        e.preventDefault();\n      }\n    }\n  };\n\n  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    if (e.target.value.length > 2) {\n      controller.updateText(e.target.value);\n      setFocus(true);\n    }\n  };\n\n  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    setValue(e.target.value);\n    if (e.target.value.length > 2) {\n      controller.updateText(e.target.value);\n    }\n  };\n\n  const handleSuggestionClick = (value: string) => {\n    setValue(value);\n    controller.selectSuggestion(value);\n  };\n\n  const handleMouseDown = (e: Event) => {\n    if ((e.target as HTMLElement)?.closest('.header__search')) {\n      if ((e.target as HTMLElement).className === 'header__search-trigger') {\n        return;\n      } else {\n        setOpen(true);\n      }\n    } else {\n      if (open) {\n        setOpen(false);\n        document.querySelector('.header')?.classList.remove('mobile-search');\n      }\n    }\n  };\n\n  const handleDidYouMean = (e: CustomEventInit) => {\n    const query = e.detail.query;\n    setValue(query);\n  };\n\n  const handleClear = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n    e.preventDefault();\n    setValue('');\n    controller.updateText('');\n  };\n\n  const handleSearchTrigger = () => {\n    setOpen(prev => !prev);\n  };\n\n  const handleInputBlur = (e: React.FocusEvent<HTMLElement>) => {\n    if (e.relatedTarget) {\n      if (!(e.relatedTarget as HTMLElement)?.closest('.header__search')) {\n        setOpen(false);\n        setFocus(false);\n      }\n    } else {\n      return;\n    }\n  };\n\n  const handleInputFocus = (e: React.FocusEvent<HTMLElement>) => {\n    const _input = e.currentTarget;\n    setFocus(true);\n\n    const parentHeader = _input.closest('.header');\n    if (parentHeader?.classList.contains('open')) {\n      parentHeader.classList.add('mobile-search');\n    }\n    if (isTablet) {\n      setTimeout(() => {\n        _input.scrollIntoView({ behavior: 'smooth' });\n      }, 320);\n    }\n  };\n\n  const handleIconSearchClick = () => {\n    controller.updateText(value);\n    controller.submit();\n  };\n\n  useEffect(() => {\n    controller.subscribe(() => setState(controller.state));\n    window.addEventListener(\n      SEARCH_BOX_EVENTS.updateDidYouMean,\n      handleDidYouMean\n    );\n\n    return () => {\n      window.removeEventListener(\n        SEARCH_BOX_EVENTS.updateDidYouMean,\n        handleDidYouMean\n      );\n    };\n  }, []);\n\n  useEffect(() => {\n    if (listRef.current) {\n      rovingIndex({\n        element: listRef.current,\n        target: '.predictive-search__item'\n      });\n    }\n  }, [state.suggestions]);\n\n  useEffect(() => {\n    if (input.current && open) {\n      input.current.focus();\n    }\n\n    window.addEventListener('mousedown', e => handleMouseDown(e));\n    return () => {\n      window.removeEventListener('mousedown', e => handleMouseDown(e));\n    };\n  }, [open, input.current]);\n\n  if (state.redirectTo) {\n    const { redirectTo, value, analytics } = state;\n    const data = JSON.stringify({ value, analytics });\n    secureStorage.set(SEARCH_KEYS.globalSearch, data);\n    window.location.href = redirectTo;\n  }\n\n  if (!open) {\n    return (\n      <button\n        className=\"header__search-trigger\"\n        title={searchLabel}\n        aria-label={searchLabel}\n        onClick={handleSearchTrigger}\n        data-layer='[{\"event\": \"navigation\", \"event_category\": \"navigation\", \"event_action\": \"top nav\", \"event_label\":\"search\" }]'\n      >\n        {searchLabel}\n      </button>\n    );\n  }\n\n  return (\n    <div onKeyDown={e => handleKeyDown(e)}>\n      <div className=\"field field--search\">\n        <input\n          className=\"field__input header__search-input \"\n          type=\"text\"\n          id={`searchbox-${id}`}\n          name=\"search\"\n          placeholder={searchPlaceholder}\n          value={value}\n          onChange={handleChange}\n          onInput={handleInputChange}\n          ref={input}\n          onFocus={handleInputFocus}\n          onBlur={e => handleInputBlur(e)}\n        />\n        {state.suggestions.length > 0 && value.length > 2 && focus && (\n          <ul\n            className=\"predictive-search__list header__predictive-search\"\n            ref={listRef}\n            onFocus={() => setFocus(true)}\n          >\n            {state.suggestions.map((suggestion, index) => {\n              const value = suggestion.rawValue;\n              if (maxSuggestions && index >= maxSuggestions - 1) {\n                return null;\n              }\n              return (\n                <li key={value}>\n                  <button\n                    className=\"predictive-search__item\"\n                    title={suggestion.rawValue}\n                    onClick={() => handleSuggestionClick(value)}\n                    dangerouslySetInnerHTML={{\n                      __html: suggestion.highlightedValue\n                    }}\n                    onFocus={() => {\n                      setFocus(true);\n                    }}\n                  />\n                </li>\n              );\n            })}\n            <li>\n              <button\n                className=\"predictive-search__item link link--arrow link--small\"\n                title={viewResults}\n                onClick={() => {\n                  controller.updateText(value);\n                  controller.submit();\n                }}\n                onFocus={() => {\n                  setFocus(true);\n                }}\n              >\n                <span>{viewResults}</span>\n              </button>\n            </li>\n          </ul>\n        )}\n        {value.length > 0 && (\n          <button\n            className=\"field__input-close header__input-close\"\n            title={clearLabel}\n            aria-label={clearLabel}\n            onClick={handleClear}\n          ></button>\n        )}\n        <button\n          className=\"field__input-search header__input-search\"\n          title={searchLabel}\n          aria-label={searchLabel}\n          onClick={handleIconSearchClick}\n          onBlur={e => handleInputBlur(e)}\n          disabled={state.value.length === 0}\n        ></button>\n      </div>\n    </div>\n  );\n};\n","import React from 'react';\n\nimport {\n  StandaloneSearchBoxOptions,\n  buildStandaloneSearchBox,\n  SearchEngine\n} from '@coveo/headless';\nimport { headlessEngineSearch } from '../../engine';\nimport { StandaloneSearchBox } from '../../components/standalone-searchbox';\n\ntype StandaloneSearchboxProps = {\n  labels: string;\n  resultsPage: string;\n};\n\nfunction StandaloneSearchbox({\n  labels,\n  resultsPage\n}: StandaloneSearchboxProps) {\n  const labelsObj = JSON.parse(labels);\n  const options: StandaloneSearchBoxOptions = {\n    numberOfSuggestions: 4,\n    redirectionUrl: resultsPage ? resultsPage : '/',\n    highlightOptions: {\n      exactMatchDelimiters: {\n        open: '<strong>',\n        close: '</strong>'\n      }\n    }\n  };\n\n  const searchBoxController = buildStandaloneSearchBox(\n    headlessEngineSearch as SearchEngine,\n    {\n      options\n    }\n  );\n\n  return (\n    <StandaloneSearchBox\n      controller={searchBoxController}\n      searchLabel={labelsObj.search}\n      searchPlaceholder={labelsObj.placeholder}\n      submitLabel={labelsObj.search}\n      clearLabel={labelsObj.clear}\n      viewResults={labelsObj.viewResults}\n    />\n  );\n}\n\nexport default StandaloneSearchbox;\n"],"names":["SEARCH_BOX_EVENTS","StandaloneSearchBox","props","id","useId","controller","searchLabel","searchPlaceholder","clearLabel","viewResults","maxSuggestions","state","setState","useState","value","setValue","focus","setFocus","open","setOpen","listRef","useRef","input","isEnterKey","handleKeyDown","firstElement","_a","lastElement","_b","_c","_d","handleInputChange","handleChange","handleSuggestionClick","handleMouseDown","handleDidYouMean","query","handleClear","handleSearchTrigger","prev","handleInputBlur","handleInputFocus","_input","parentHeader","isTablet","handleIconSearchClick","useEffect","rovingIndex","redirectTo","analytics","data","secureStorage","SEARCH_KEYS","React","suggestion","index","StandaloneSearchbox","labels","resultsPage","labelsObj","searchBoxController","buildStandaloneSearchBox","headlessEngineSearch"],"mappings":"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"}