symbol-palette-item.js 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import { useEffect, useRef } from 'react'
  2. import { OverlayTrigger, Tooltip } from 'react-bootstrap'
  3. import PropTypes from 'prop-types'
  4. export default function SymbolPaletteItem({
  5. focused,
  6. handleSelect,
  7. handleKeyDown,
  8. symbol,
  9. }) {
  10. const buttonRef = useRef(null)
  11. // call focus() on this item when appropriate
  12. useEffect(() => {
  13. if (
  14. focused &&
  15. buttonRef.current &&
  16. document.activeElement?.closest('.symbol-palette-items')
  17. ) {
  18. buttonRef.current.focus()
  19. }
  20. }, [focused])
  21. return (
  22. <OverlayTrigger
  23. placement="top"
  24. trigger={['hover', 'focus']}
  25. overlay={
  26. <Tooltip id={`tooltip-symbol-${symbol.codepoint}`}>
  27. <div className="symbol-palette-item-description">
  28. {symbol.description}
  29. </div>
  30. <div className="symbol-palette-item-command">{symbol.command}</div>
  31. {symbol.notes && (
  32. <div className="symbol-palette-item-notes">{symbol.notes}</div>
  33. )}
  34. </Tooltip>
  35. }
  36. >
  37. <button
  38. key={symbol.codepoint}
  39. className="symbol-palette-item"
  40. onClick={() => handleSelect(symbol)}
  41. onKeyDown={handleKeyDown}
  42. tabIndex={focused ? 0 : -1}
  43. ref={buttonRef}
  44. role="option"
  45. aria-label={symbol.description}
  46. aria-selected={focused ? 'true' : 'false'}
  47. >
  48. {symbol.character}
  49. </button>
  50. </OverlayTrigger>
  51. )
  52. }
  53. SymbolPaletteItem.propTypes = {
  54. symbol: PropTypes.shape({
  55. codepoint: PropTypes.string.isRequired,
  56. description: PropTypes.string.isRequired,
  57. command: PropTypes.string.isRequired,
  58. character: PropTypes.string.isRequired,
  59. notes: PropTypes.string,
  60. }),
  61. handleKeyDown: PropTypes.func.isRequired,
  62. handleSelect: PropTypes.func.isRequired,
  63. focused: PropTypes.bool,
  64. }