{"version":3,"file":"Typeahead.mjs","sources":["../../../../src/components/Typeahead/Typeahead.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport { isEqual } from 'lodash';\nimport { createRef, PureComponent } from 'react';\nimport * as React from 'react';\nimport ReactDOM from 'react-dom';\nimport { FixedSizeList } from 'react-window';\n\nimport { GrafanaTheme2, ThemeContext } from '@grafana/data';\n\nimport { CompletionItem, CompletionItemGroup, CompletionItemKind } from '../../types/completion';\nimport { flattenGroupItems, calculateLongestLabel, calculateListSizes } from '../../utils/typeahead';\n\nimport { TypeaheadInfo } from './TypeaheadInfo';\nimport { TypeaheadItem } from './TypeaheadItem';\n\nconst modulo = (a: number, n: number) => a - n * Math.floor(a / n);\n\ninterface Props {\n  origin: string;\n  groupedItems: CompletionItemGroup[];\n  prefix?: string;\n  menuRef?: (el: Typeahead) => void;\n  onSelectSuggestion?: (suggestion: CompletionItem) => void;\n  isOpen?: boolean;\n}\n\nexport interface State {\n  allItems: CompletionItem[];\n  listWidth: number;\n  listHeight: number;\n  itemHeight: number;\n  hoveredItem: number | null;\n  typeaheadIndex: number | null;\n}\n\nexport class Typeahead extends PureComponent<Props, State> {\n  static contextType = ThemeContext;\n  context!: React.ContextType<typeof ThemeContext>;\n  listRef = createRef<FixedSizeList>();\n\n  state: State = {\n    hoveredItem: null,\n    typeaheadIndex: null,\n    allItems: [],\n    listWidth: -1,\n    listHeight: -1,\n    itemHeight: -1,\n  };\n\n  componentDidMount = () => {\n    if (this.props.menuRef) {\n      this.props.menuRef(this);\n    }\n\n    document.addEventListener('selectionchange', this.handleSelectionChange);\n\n    const allItems = flattenGroupItems(this.props.groupedItems);\n    const longestLabel = calculateLongestLabel(allItems);\n    const { listWidth, listHeight, itemHeight } = calculateListSizes(this.context, allItems, longestLabel);\n    this.setState({\n      listWidth,\n      listHeight,\n      itemHeight,\n      allItems,\n    });\n  };\n\n  componentWillUnmount = () => {\n    document.removeEventListener('selectionchange', this.handleSelectionChange);\n  };\n\n  handleSelectionChange = () => {\n    this.forceUpdate();\n  };\n\n  componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>) => {\n    if (\n      this.state.typeaheadIndex !== null &&\n      prevState.typeaheadIndex !== this.state.typeaheadIndex &&\n      this.listRef &&\n      this.listRef.current\n    ) {\n      if (this.state.typeaheadIndex === 1) {\n        this.listRef.current.scrollToItem(0); // special case for handling the first group label\n        return;\n      }\n      this.listRef.current.scrollToItem(this.state.typeaheadIndex);\n    }\n\n    if (isEqual(prevProps.groupedItems, this.props.groupedItems) === false) {\n      const allItems = flattenGroupItems(this.props.groupedItems);\n      const longestLabel = calculateLongestLabel(allItems);\n      const { listWidth, listHeight, itemHeight } = calculateListSizes(this.context, allItems, longestLabel);\n      this.setState({ listWidth, listHeight, itemHeight, allItems, typeaheadIndex: null });\n    }\n  };\n\n  onMouseEnter = (index: number) => {\n    this.setState({\n      hoveredItem: index,\n    });\n  };\n\n  onMouseLeave = () => {\n    this.setState({\n      hoveredItem: null,\n    });\n  };\n\n  moveMenuIndex = (moveAmount: number) => {\n    const itemCount = this.state.allItems.length;\n    if (itemCount) {\n      // Select next suggestion\n      const typeaheadIndex = this.state.typeaheadIndex || 0;\n      let newTypeaheadIndex = modulo(typeaheadIndex + moveAmount, itemCount);\n\n      if (this.state.allItems[newTypeaheadIndex].kind === CompletionItemKind.GroupTitle) {\n        newTypeaheadIndex = modulo(newTypeaheadIndex + moveAmount, itemCount);\n      }\n\n      this.setState({\n        typeaheadIndex: newTypeaheadIndex,\n      });\n\n      return;\n    }\n  };\n\n  insertSuggestion = () => {\n    if (this.props.onSelectSuggestion && this.state.typeaheadIndex !== null) {\n      this.props.onSelectSuggestion(this.state.allItems[this.state.typeaheadIndex]);\n    }\n  };\n\n  get menuPosition(): string {\n    // Exit for unit tests\n    if (!window.getSelection) {\n      return '';\n    }\n\n    const selection = window.getSelection();\n    const node = selection && selection.anchorNode;\n\n    // Align menu overlay to editor node\n    if (node && node.parentElement) {\n      // Read from DOM\n      const rect = node.parentElement.getBoundingClientRect();\n      const scrollX = window.scrollX;\n      const scrollY = window.scrollY;\n\n      return `position: absolute; display: flex; top: ${rect.top + scrollY + rect.height + 6}px; left: ${\n        rect.left + scrollX - 2\n      }px`;\n    }\n\n    return '';\n  }\n\n  render() {\n    const { prefix, isOpen = false, origin } = this.props;\n    const { allItems, listWidth, listHeight, itemHeight, hoveredItem, typeaheadIndex } = this.state;\n    const styles = getStyles(this.context);\n\n    const showDocumentation = hoveredItem || typeaheadIndex;\n    const documentationItem = allItems[hoveredItem ? hoveredItem : typeaheadIndex || 0];\n\n    return (\n      <Portal origin={origin} isOpen={isOpen} style={this.menuPosition}>\n        <ul role=\"menu\" className={styles.typeahead} data-testid=\"typeahead\">\n          <FixedSizeList\n            ref={this.listRef}\n            itemCount={allItems.length}\n            itemSize={itemHeight}\n            itemKey={(index) => {\n              const item = allItems && allItems[index];\n              const key = item ? `${index}-${item.label}` : `${index}`;\n              return key;\n            }}\n            width={listWidth}\n            height={listHeight}\n          >\n            {({ index, style }) => {\n              const item = allItems && allItems[index];\n              if (!item) {\n                return null;\n              }\n\n              return (\n                <TypeaheadItem\n                  onClickItem={() => (this.props.onSelectSuggestion ? this.props.onSelectSuggestion(item) : {})}\n                  isSelected={typeaheadIndex === null ? false : allItems[typeaheadIndex] === item}\n                  item={item}\n                  prefix={prefix}\n                  style={style}\n                  onMouseEnter={() => this.onMouseEnter(index)}\n                  onMouseLeave={this.onMouseLeave}\n                />\n              );\n            }}\n          </FixedSizeList>\n        </ul>\n\n        {showDocumentation && <TypeaheadInfo height={listHeight} item={documentationItem} />}\n      </Portal>\n    );\n  }\n}\n\ninterface PortalProps {\n  index?: number;\n  isOpen: boolean;\n  origin: string;\n  style: string;\n}\n\nclass Portal extends PureComponent<React.PropsWithChildren<PortalProps>, {}> {\n  node: HTMLElement;\n\n  constructor(props: React.PropsWithChildren<PortalProps>) {\n    super(props);\n    const { index = 0, origin = 'query', style } = props;\n    this.node = document.createElement('div');\n    this.node.setAttribute('style', style);\n    this.node.classList.add(`slate-typeahead-${origin}-${index}`);\n    document.body.appendChild(this.node);\n  }\n\n  componentWillUnmount() {\n    document.body.removeChild(this.node);\n  }\n\n  render() {\n    if (this.props.isOpen) {\n      this.node.setAttribute('style', this.props.style);\n      this.node.classList.add(`slate-typeahead--open`);\n      return ReactDOM.createPortal(this.props.children, this.node);\n    } else {\n      this.node.classList.remove(`slate-typeahead--open`);\n    }\n\n    return null;\n  }\n}\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n  typeahead: css({\n    position: 'relative',\n    zIndex: theme.zIndex.typeahead,\n    borderRadius: theme.shape.radius.default,\n    border: `1px solid ${theme.components.panel.borderColor}`,\n    maxHeight: '66vh',\n    overflowY: 'scroll',\n    overflowX: 'hidden',\n    outline: 'none',\n    listStyle: 'none',\n    background: theme.components.panel.background,\n    color: theme.colors.text.primary,\n    boxShadow: theme.shadows.z2,\n\n    strong: {\n      color: theme.v1.palette.yellow,\n    },\n  }),\n});\n"],"names":[],"mappings":"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"}