button-menu.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import { FC, memo, useRef } from 'react'
  2. import { Button, ListGroup, Overlay, Popover } from 'react-bootstrap'
  3. import Icon from '../../../../shared/components/icon'
  4. import useDropdown from '../../../../shared/hooks/use-dropdown'
  5. import Tooltip from '../../../../shared/components/tooltip'
  6. import { EditorView } from '@codemirror/view'
  7. import { emitToolbarEvent } from '../../extensions/toolbar/utils/analytics'
  8. import { useCodeMirrorViewContext } from '../codemirror-editor'
  9. import MaterialIcon from '../../../../shared/components/material-icon'
  10. export const ToolbarButtonMenu: FC<{
  11. id: string
  12. label: string
  13. icon: string
  14. materialIcon?: boolean
  15. altCommand?: (view: EditorView) => void
  16. }> = memo(function ButtonMenu({
  17. icon,
  18. id,
  19. label,
  20. materialIcon,
  21. altCommand,
  22. children,
  23. }) {
  24. const target = useRef<any>(null)
  25. const { open, onToggle, ref } = useDropdown()
  26. const view = useCodeMirrorViewContext()
  27. const button = (
  28. <Button
  29. type="button"
  30. className="ol-cm-toolbar-button"
  31. aria-label={label}
  32. bsStyle={null}
  33. onMouseDown={event => {
  34. event.preventDefault()
  35. event.stopPropagation()
  36. }}
  37. onClick={event => {
  38. if (event.altKey && altCommand && open === false) {
  39. emitToolbarEvent(view, id)
  40. event.preventDefault()
  41. altCommand(view)
  42. view.focus()
  43. } else {
  44. onToggle(!open)
  45. }
  46. }}
  47. ref={target}
  48. >
  49. {materialIcon ? <MaterialIcon type={icon} /> : <Icon type={icon} fw />}
  50. </Button>
  51. )
  52. const overlay = (
  53. <Overlay
  54. show={open}
  55. target={target.current}
  56. placement="bottom"
  57. container={view.dom}
  58. containerPadding={0}
  59. animation
  60. onHide={() => onToggle(false)}
  61. >
  62. <Popover
  63. id={`${id}-menu`}
  64. ref={ref}
  65. className="ol-cm-toolbar-button-menu-popover"
  66. >
  67. <ListGroup
  68. role="menu"
  69. onClick={() => {
  70. onToggle(false)
  71. }}
  72. >
  73. {children}
  74. </ListGroup>
  75. </Popover>
  76. </Overlay>
  77. )
  78. if (!label) {
  79. return (
  80. <>
  81. {button}
  82. {overlay}
  83. </>
  84. )
  85. }
  86. return (
  87. <>
  88. <Tooltip
  89. hidden={open}
  90. id={id}
  91. description={<div>{label}</div>}
  92. overlayProps={{ placement: 'bottom' }}
  93. >
  94. {button}
  95. </Tooltip>
  96. {overlay}
  97. </>
  98. )
  99. })