button-menu.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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. rootClose
  61. onHide={() => onToggle(false)}
  62. >
  63. <Popover
  64. id={`${id}-menu`}
  65. ref={ref}
  66. className="ol-cm-toolbar-button-menu-popover"
  67. >
  68. <ListGroup
  69. role="menu"
  70. onClick={() => {
  71. onToggle(false)
  72. }}
  73. >
  74. {children}
  75. </ListGroup>
  76. </Popover>
  77. </Overlay>
  78. )
  79. if (!label) {
  80. return (
  81. <>
  82. {button}
  83. {overlay}
  84. </>
  85. )
  86. }
  87. return (
  88. <>
  89. <Tooltip
  90. hidden={open}
  91. id={id}
  92. description={<div>{label}</div>}
  93. overlayProps={{ placement: 'bottom' }}
  94. >
  95. {button}
  96. </Tooltip>
  97. {overlay}
  98. </>
  99. )
  100. })