toolbar-button.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import { memo, useCallback } from 'react'
  2. import { EditorView } from '@codemirror/view'
  3. import { useCodeMirrorViewContext } from '../codemirror-context'
  4. import classnames from 'classnames'
  5. import { emitToolbarEvent } from '../../extensions/toolbar/utils/analytics'
  6. import Icon from '../../../../shared/components/icon'
  7. import MaterialIcon from '@/shared/components/material-icon'
  8. import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
  9. import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
  10. import { bsVersion } from '@/features/utils/bootstrap-5'
  11. export const ToolbarButton = memo<{
  12. id: string
  13. className?: string
  14. label: string
  15. command?: (view: EditorView) => void
  16. active?: boolean
  17. disabled?: boolean
  18. icon: string
  19. textIcon?: boolean
  20. hidden?: boolean
  21. shortcut?: string
  22. }>(function ToolbarButton({
  23. id,
  24. className,
  25. label,
  26. command,
  27. active = false,
  28. disabled,
  29. icon,
  30. textIcon = false,
  31. hidden = false,
  32. shortcut,
  33. }) {
  34. const view = useCodeMirrorViewContext()
  35. const handleMouseDown = useCallback(event => {
  36. event.preventDefault()
  37. }, [])
  38. const handleClick = useCallback(
  39. event => {
  40. emitToolbarEvent(view, id)
  41. if (command) {
  42. event.preventDefault()
  43. command(view)
  44. view.focus()
  45. }
  46. },
  47. [command, view, id]
  48. )
  49. const button = (
  50. <button
  51. className={classnames(
  52. 'ol-cm-toolbar-button',
  53. bsVersion({ bs3: 'btn' }),
  54. className,
  55. {
  56. active,
  57. hidden,
  58. }
  59. )}
  60. aria-label={label}
  61. onMouseDown={handleMouseDown}
  62. onClick={!disabled ? handleClick : undefined}
  63. aria-disabled={disabled}
  64. type="button"
  65. >
  66. {textIcon ? (
  67. icon
  68. ) : (
  69. <BootstrapVersionSwitcher
  70. bs3={<Icon type={icon} fw accessibilityLabel={label} />}
  71. bs5={<MaterialIcon type={icon} accessibilityLabel={label} />}
  72. />
  73. )}
  74. </button>
  75. )
  76. if (!label) {
  77. return button
  78. }
  79. const description = (
  80. <>
  81. <div>{label}</div>
  82. {shortcut && <div>{shortcut}</div>}
  83. </>
  84. )
  85. return (
  86. <OLTooltip
  87. id={id}
  88. description={description}
  89. overlayProps={{ placement: 'bottom' }}
  90. >
  91. {button}
  92. </OLTooltip>
  93. )
  94. })