button-menu.tsx 2.3 KB

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