variable-option.tsx 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import { memo } from 'react'
  2. import { MenuOption } from '@lexical/react/LexicalTypeaheadMenuPlugin'
  3. export class VariableOption extends MenuOption {
  4. title: string
  5. icon?: JSX.Element
  6. extraElement?: JSX.Element
  7. keywords: Array<string>
  8. keyboardShortcut?: string
  9. onSelect: (queryString: string) => void
  10. constructor(
  11. title: string,
  12. options: {
  13. icon?: JSX.Element
  14. extraElement?: JSX.Element
  15. keywords?: Array<string>
  16. keyboardShortcut?: string
  17. onSelect: (queryString: string) => void
  18. },
  19. ) {
  20. super(title)
  21. this.title = title
  22. this.keywords = options.keywords || []
  23. this.icon = options.icon
  24. this.extraElement = options.extraElement
  25. this.keyboardShortcut = options.keyboardShortcut
  26. this.onSelect = options.onSelect.bind(this)
  27. }
  28. }
  29. type VariableMenuItemProps = {
  30. startIndex: number
  31. index: number
  32. isSelected: boolean
  33. onClick: (index: number, option: VariableOption) => void
  34. onMouseEnter: (index: number, option: VariableOption) => void
  35. option: VariableOption
  36. queryString: string | null
  37. }
  38. export const VariableMenuItem = memo(({
  39. startIndex,
  40. index,
  41. isSelected,
  42. onClick,
  43. onMouseEnter,
  44. option,
  45. queryString,
  46. }: VariableMenuItemProps) => {
  47. const title = option.title
  48. let before = title
  49. let middle = ''
  50. let after = ''
  51. if (queryString) {
  52. const regex = new RegExp(queryString, 'i')
  53. const match = regex.exec(option.title)
  54. if (match) {
  55. before = title.substring(0, match.index)
  56. middle = match[0]
  57. after = title.substring(match.index + match[0].length)
  58. }
  59. }
  60. return (
  61. <div
  62. key={option.key}
  63. className={`
  64. flex items-center px-3 h-6 rounded-md hover:bg-primary-50 cursor-pointer
  65. ${isSelected && 'bg-primary-50'}
  66. `}
  67. tabIndex={-1}
  68. ref={option.setRefElement}
  69. onMouseEnter={() => onMouseEnter(index + startIndex, option)}
  70. onClick={() => onClick(index + startIndex, option)}>
  71. <div className='mr-2'>
  72. {option.icon}
  73. </div>
  74. <div className='grow text-[13px] text-gray-900 truncate' title={option.title}>
  75. {before}
  76. <span className='text-[#2970FF]'>{middle}</span>
  77. {after}
  78. </div>
  79. {option.extraElement}
  80. </div>
  81. )
  82. })
  83. VariableMenuItem.displayName = 'VariableMenuItem'