UNPKG

@grafana/ui

Version:
205 lines (198 loc) • 7.56 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var jsxRuntime = require('react/jsx-runtime'); var css = require('@emotion/css'); var lodash = require('lodash'); var React = require('react'); var ReactDOM = require('react-dom'); var reactWindow = require('react-window'); var data = require('@grafana/data'); var completion = require('../../types/completion.cjs'); var typeahead = require('../../utils/typeahead.cjs'); var TypeaheadInfo = require('./TypeaheadInfo.cjs'); var TypeaheadItem = require('./TypeaheadItem.cjs'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } var ReactDOM__default = /*#__PURE__*/_interopDefaultCompat(ReactDOM); "use strict"; const modulo = (a, n) => a - n * Math.floor(a / n); class Typeahead extends React.PureComponent { constructor() { super(...arguments); this.listRef = React.createRef(); this.state = { hoveredItem: null, typeaheadIndex: null, allItems: [], listWidth: -1, listHeight: -1, itemHeight: -1 }; this.componentDidMount = () => { if (this.props.menuRef) { this.props.menuRef(this); } document.addEventListener("selectionchange", this.handleSelectionChange); const allItems = typeahead.flattenGroupItems(this.props.groupedItems); const longestLabel = typeahead.calculateLongestLabel(allItems); const { listWidth, listHeight, itemHeight } = typeahead.calculateListSizes(this.context, allItems, longestLabel); this.setState({ listWidth, listHeight, itemHeight, allItems }); }; this.componentWillUnmount = () => { document.removeEventListener("selectionchange", this.handleSelectionChange); }; this.handleSelectionChange = () => { this.forceUpdate(); }; this.componentDidUpdate = (prevProps, prevState) => { if (this.state.typeaheadIndex !== null && prevState.typeaheadIndex !== this.state.typeaheadIndex && this.listRef && this.listRef.current) { if (this.state.typeaheadIndex === 1) { this.listRef.current.scrollToItem(0); return; } this.listRef.current.scrollToItem(this.state.typeaheadIndex); } if (lodash.isEqual(prevProps.groupedItems, this.props.groupedItems) === false) { const allItems = typeahead.flattenGroupItems(this.props.groupedItems); const longestLabel = typeahead.calculateLongestLabel(allItems); const { listWidth, listHeight, itemHeight } = typeahead.calculateListSizes(this.context, allItems, longestLabel); this.setState({ listWidth, listHeight, itemHeight, allItems, typeaheadIndex: null }); } }; this.onMouseEnter = (index) => { this.setState({ hoveredItem: index }); }; this.onMouseLeave = () => { this.setState({ hoveredItem: null }); }; this.moveMenuIndex = (moveAmount) => { const itemCount = this.state.allItems.length; if (itemCount) { const typeaheadIndex = this.state.typeaheadIndex || 0; let newTypeaheadIndex = modulo(typeaheadIndex + moveAmount, itemCount); if (this.state.allItems[newTypeaheadIndex].kind === completion.CompletionItemKind.GroupTitle) { newTypeaheadIndex = modulo(newTypeaheadIndex + moveAmount, itemCount); } this.setState({ typeaheadIndex: newTypeaheadIndex }); return; } }; this.insertSuggestion = () => { if (this.props.onSelectSuggestion && this.state.typeaheadIndex !== null) { this.props.onSelectSuggestion(this.state.allItems[this.state.typeaheadIndex]); } }; } get menuPosition() { if (!window.getSelection) { return ""; } const selection = window.getSelection(); const node = selection && selection.anchorNode; if (node && node.parentElement) { const rect = node.parentElement.getBoundingClientRect(); const scrollX = window.scrollX; const scrollY = window.scrollY; return `position: absolute; display: flex; top: ${rect.top + scrollY + rect.height + 6}px; left: ${rect.left + scrollX - 2}px`; } return ""; } render() { const { prefix, isOpen = false, origin } = this.props; const { allItems, listWidth, listHeight, itemHeight, hoveredItem, typeaheadIndex } = this.state; const styles = getStyles(this.context); const showDocumentation = hoveredItem || typeaheadIndex; const documentationItem = allItems[hoveredItem ? hoveredItem : typeaheadIndex || 0]; return /* @__PURE__ */ jsxRuntime.jsxs(Portal, { origin, isOpen, style: this.menuPosition, children: [ /* @__PURE__ */ jsxRuntime.jsx("ul", { role: "menu", className: styles.typeahead, "data-testid": "typeahead", children: /* @__PURE__ */ jsxRuntime.jsx( reactWindow.FixedSizeList, { ref: this.listRef, itemCount: allItems.length, itemSize: itemHeight, itemKey: (index) => { const item = allItems && allItems[index]; const key = item ? `${index}-${item.label}` : `${index}`; return key; }, width: listWidth, height: listHeight, children: ({ index, style }) => { const item = allItems && allItems[index]; if (!item) { return null; } return /* @__PURE__ */ jsxRuntime.jsx( TypeaheadItem.TypeaheadItem, { onClickItem: () => this.props.onSelectSuggestion ? this.props.onSelectSuggestion(item) : {}, isSelected: typeaheadIndex === null ? false : allItems[typeaheadIndex] === item, item, prefix, style, onMouseEnter: () => this.onMouseEnter(index), onMouseLeave: this.onMouseLeave } ); } } ) }), showDocumentation && /* @__PURE__ */ jsxRuntime.jsx(TypeaheadInfo.TypeaheadInfo, { height: listHeight, item: documentationItem }) ] }); } } Typeahead.contextType = data.ThemeContext; class Portal extends React.PureComponent { constructor(props) { super(props); const { index = 0, origin = "query", style } = props; this.node = document.createElement("div"); this.node.setAttribute("style", style); this.node.classList.add(`slate-typeahead-${origin}-${index}`); document.body.appendChild(this.node); } componentWillUnmount() { document.body.removeChild(this.node); } render() { if (this.props.isOpen) { this.node.setAttribute("style", this.props.style); this.node.classList.add(`slate-typeahead--open`); return ReactDOM__default.default.createPortal(this.props.children, this.node); } else { this.node.classList.remove(`slate-typeahead--open`); } return null; } } const getStyles = (theme) => ({ typeahead: css.css({ position: "relative", zIndex: theme.zIndex.typeahead, borderRadius: theme.shape.radius.default, border: `1px solid ${theme.components.panel.borderColor}`, maxHeight: "66vh", overflowY: "scroll", overflowX: "hidden", outline: "none", listStyle: "none", background: theme.components.panel.background, color: theme.colors.text.primary, boxShadow: theme.shadows.z2, strong: { color: theme.v1.palette.yellow } }) }); exports.Typeahead = Typeahead; //# sourceMappingURL=Typeahead.cjs.map