UNPKG

@unicef/material-slate

Version:

Material UI rich text editor based on Slate for react

203 lines (184 loc) 5.96 kB
import React from 'react' import { useSlate } from 'slate-react' import PropTypes from 'prop-types' import IconButton from '@material-ui/core/IconButton' import Tooltip from '@material-ui/core/Tooltip' import CropSquareOutlined from '@material-ui/icons/CropSquareOutlined' /** * ToolbarButton is the base button for any button on the toolbars. * It requires the `type` of action to perform and the format that will be added. * * It displays a tooltip text on hover. If tooltip text is not passed as a prop it will use the capitalized text of the format */ const ToolbarButton = React.forwardRef( ( { tooltip, placement, icon, type, disabled, disableOnSelection, disableOnCollapse, format, onMouseDown, isActive, ...rest }, ref ) => { const editor = useSlate() /** * If no tooltip prop is passed it generates a default based on the format string. * Converts - into spaces and uppercases the first letter of the first word. */ const defaultTooltip = () => { return (format.charAt(0).toUpperCase() + format.substring(1)).replace( '-', ' ' ) } /** * Toggles mark| block and forwards the onMouseDown event */ const handleOnMouseDown = event => { event.preventDefault() switch (type) { case 'mark': editor.toggleMark(format) break case 'block': editor.toggleBlock(format) } onMouseDown && onMouseDown({ editor, format, type, event }) } const checkIsActive = () => { if (isActive) { return isActive() } switch (type) { case 'mark': return editor.isMarkActive(format) case 'block': return editor.isBlockActive(format) case 'link': return editor.isNodeTypeActive(format) } return } /** * Conditionally disables the button */ const isDisabled = () => { let disabled = false disabled = disableOnSelection ? editor.isSelectionExpanded() : false disabled = disableOnCollapse ? editor.isSelectionCollapsed() : disabled return disabled } return disabled || isDisabled() ? ( <IconButton aria-label={tooltip ? tooltip : defaultTooltip()} ref={ref} color={checkIsActive() ? 'secondary' : 'default'} onMouseDown={event => handleOnMouseDown(event)} disabled={disabled || isDisabled()} {...rest} > {icon} </IconButton> ) : ( <Tooltip title={tooltip ? tooltip : defaultTooltip()} placement={placement} > <IconButton aria-label={tooltip ? tooltip : defaultTooltip()} ref={ref} color={checkIsActive() ? 'secondary' : 'default'} onMouseDown={event => handleOnMouseDown(event)} disabled={disabled || isDisabled()} {...rest} > {icon} </IconButton> </Tooltip> ) } ) export default ToolbarButton ToolbarButton.defaultProps = { placement: 'top', icon: <CropSquareOutlined />, disableOnCollapse: false, disableOnSelection: false, } // PropTypes ToolbarButton.propTypes = { /** * Text displayed on the button tooltip. By Default it is the capitalized `format` string. * For instance, `bold` is displayed as `Bold`. */ tooltip: PropTypes.string, /** * Location where the tooltip will appear. * It can be `top`, `bottom`, `left`, `right`. Defaults to top. */ placement: PropTypes.string, /** * Toolbar button has the option of adding to the editor value marks and blocks. * * `mark` can be added to the editor value when you want to add something like `bold`, `italic`... * Marks are rendered into HTML in `renderLeaf` of `MaterialEditable` * * `block` to be added to the editor `value` when the button is pressed. For example: `header1`, `numbered-list`... * `renderElement` of the `RichEditable` component will need to handle the actual conversion from mark to HTML/Component on render time. * * If you don't want to add a mark or a block do not set the prop or use whatever string. * You can perform the action the button triggers using onMouseDown(). */ type: PropTypes.string, /** * * The string that identifies the format of the block or mark to be added. For example: `bold`, `header1`... */ format: PropTypes.string.isRequired, /** * * When a button is active it means the button is highlighted. For example, if in current position of the cursor, * the text is bold, the bold button should be active. * * isActive is a function that returns true/false to indicate the status of the mark/block. * Set this function if you need to handle anything other than standard mark or blocks. */ isActive: PropTypes.func, /** * Unconditionally disables the button * * Disable a button means that the button cannot be clicked (note it is not the opposite of isActive) */ disabled: PropTypes.bool, /** * If true, disables the button if there is a text selected on the editor. * * Disable a button means that the button cannot be clicked. * * Use either disableOnSelection or disableOnCollapse, but not both. */ disableOnSelection: PropTypes.bool, /** * If true, disables the button when there is no text selected or the editor has no focus. * * Disable a button means that button cannot be clicked. * * Use either disableOnSelection or disableOnCollapse, but not both. */ disableOnCollapse: PropTypes.bool, /** * Instance a component. The icon that will be displayed. Typically an icon from @material-ui/icons */ icon: PropTypes.object, /** * On mouse down event is passed up to the parent with props that can be deconstructed in {editor, event, mark/block} */ onMouseDown: PropTypes.func, }