{"version":3,"file":"klipyPicker.mjs","names":[],"sources":["../../../../package/common/klipyPicker/klipyPicker.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport cx from 'classnames';\nimport type { ReactElement, ReactNode } from 'react';\nimport KlipyService from 'services/klipy';\nimport type { KlipyResult } from 'services/klipy';\nimport SearchInput from '../searchInput';\nimport GifPreview from './components/gifPreview';\nimport Popover from '../popover';\nimport Button, { ButtonStyleType } from '../button';\nimport Modal from '../modal';\nimport Chip, { ChipContainer } from '../chip';\nimport GifView from './components/gifView';\nimport type { KlipyPickerLabels, KlipyPickerProps } from './klipyPicker.types';\nimport { useLabels } from '../configProvider';\n\nconst DEFAULT_LABELS: Required<KlipyPickerLabels> = {\n  search: 'Pick gif',\n};\nimport styles from './klipyPicker.module.pcss';\nimport actionButtonStyles from 'components/common/actionButtons/actionButtons.module.pcss';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { ThemeColor } from '../themeProvider/color.types';\n\nexport default function KlipyPicker({\n  className,\n  token = '',\n  isModal = false,\n  onSelect = () => undefined,\n  selected = null,\n  labels,\n}: KlipyPickerProps): ReactElement {\n  const text = useLabels('KlipyPicker', labels, DEFAULT_LABELS);\n  const klipyService = useMemo(() => new KlipyService(token), [token]);\n\n  const [searchText, setSearchText] = useState('');\n  const [currentPreviews, setCurrentPreviews] = useState<KlipyResult[]>([]);\n  const [currentSuggestions, setCurrentSuggestions] = useState<string[]>([]);\n  const [lastNext, setLastNext] = useState<string | null>(null);\n  const [isMenuOpen, setIsMenuOpen] = useState(false);\n\n  async function searchFor(query: string) {\n    setSearchText(query);\n    if (!query.trim()) {\n      setCurrentPreviews([]);\n      setCurrentSuggestions([]);\n      setLastNext(null);\n      return;\n    }\n    const [{ results: searchResults = [], next = null }, { results: suggestionResults = [] }] = await Promise.all([\n      klipyService.search(query, { limit: 18, contentfilter: 'medium' }),\n      klipyService.searchSuggestions(query),\n    ]);\n    setCurrentPreviews(searchResults);\n    setLastNext(next);\n    setCurrentSuggestions(suggestionResults);\n  }\n\n  async function handleLoadAdditional() {\n    const { results: searchResults = [], next = null } = await klipyService.search(searchText, {\n      limit: 36,\n      pos: lastNext ?? undefined,\n      contentfilter: 'medium',\n    });\n    setLastNext(next);\n    setCurrentPreviews((prev) => [...prev, ...searchResults]);\n  }\n\n  async function handlePreviewSelect(preview: KlipyResult | null) {\n    await onSelect(preview);\n    setIsMenuOpen(false);\n    if (preview) klipyService.registerShare(searchText, preview.id);\n  }\n\n  function renderSuggestions(): ReactNode {\n    return (\n      <ChipContainer inline className={styles.klipyPickerSuggestionsContainer}>\n        {currentSuggestions.map((suggestion) => (\n          <Chip\n            className={styles.klipyPickerSuggestionsItem}\n            key={suggestion}\n            text={suggestion}\n            onClick={() => searchFor(suggestion)}\n          />\n        ))}\n      </ChipContainer>\n    );\n  }\n\n  function renderPreviewPicker(): ReactNode {\n    return (\n      <GifPreview\n        previewItems={currentPreviews}\n        onSelect={handlePreviewSelect}\n        onLoadAdditional={handleLoadAdditional}\n      />\n    );\n  }\n\n  function renderSearchInput(): ReactNode {\n    return <SearchInput label={text.search} value={searchText} onDebounce={searchFor} onChange={setSearchText} />;\n  }\n\n  if (isModal) {\n    return (\n      <div className={cx(styles.klipyPicker, className)}>\n        <div className={actionButtonStyles.actionButtons}>\n          <Button onClick={() => setIsMenuOpen(true)}>Pick gif</Button>\n          {selected && (\n            <Button\n              styleType={ButtonStyleType.Filled}\n              color={ThemeColor.Error}\n              onClick={() => handlePreviewSelect(null)}\n            >\n              Remove gif\n            </Button>\n          )}\n        </div>\n        {selected && <GifView className={styles.klipyPickerSelected} src={selected} />}\n        <Modal isOpen={isMenuOpen} onClose={() => setIsMenuOpen(false)}>\n          <div className={styles.klipyPickerModalContent}>\n            {renderSearchInput()}\n            {renderSuggestions()}\n            {renderPreviewPicker()}\n          </div>\n        </Modal>\n      </div>\n    );\n  }\n\n  return (\n    <div className={cx(styles.klipyPicker, className)}>\n      <Popover\n        placement={PopoverPlacement.Bottom}\n        align={PopoverAlign.Start}\n        isOpen={currentPreviews.length > 0 && isMenuOpen}\n        onOpenChange={setIsMenuOpen}\n        // The panel opens while the user is typing in the search field, so a\n        // click back into the field must not close it again.\n        closeOnTriggerClick={false}\n        // The grid sets its own 420px cap.\n        constrainWidth={false}\n        content={\n          <>\n            {renderSuggestions()}\n            {renderPreviewPicker()}\n          </>\n        }\n      >\n        {renderSearchInput()}\n      </Popover>\n      {selected && (\n        <Button styleType={ButtonStyleType.Filled} color={ThemeColor.Error} onClick={() => handlePreviewSelect(null)}>\n          Remove gif\n        </Button>\n      )}\n      {selected && <GifView className={styles.klipyPickerSelected} src={selected} />}\n    </div>\n  );\n}\n"],"mappings":"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"}