UNPKG

kedao

Version:

Rich Text Editor Based On Draft.js

192 lines (191 loc) 7.66 kB
import React from 'react'; import Immutable, { Map } from 'immutable'; import { DefaultDraftBlockRenderMap, CompositeDecorator } from 'draft-js'; import Image from '../../components/Image'; import Video from '../../components/Video'; import Audio from '../../components/Audio'; import Embed from '../../components/Embed'; import HorizontalLine from '../../components/HorizontalLine'; import { removeBlock } from '..'; import CombineDecorators from 'draft-js-multidecorators'; import Link from '../../components/Link'; import { classNameParser } from '../style'; import styles from "./style.module.css"; const cls = classNameParser(styles); export const getBlockRenderMap = (blockRenderMap) => { let customBlockRenderMap = Map({ atomic: { element: '' }, 'code-block': { element: 'code', wrapper: React.createElement("pre", null) } }); try { if (blockRenderMap) { customBlockRenderMap = customBlockRenderMap.merge(blockRenderMap); } customBlockRenderMap = DefaultDraftBlockRenderMap.merge(customBlockRenderMap); } catch (error) { console.warn(error); } return customBlockRenderMap; }; export const getBlockRendererFn = (superProps, customBlockRendererFn) => (block) => { var _a; const { value, onChange, extendAtomics, imageEqualRatio, readOnly, imageResizable, imageControls, lock, getContainerNode, refresh } = superProps; const renderAtomicBlock = ({ contentState }) => { const entityKey = block.getEntityAt(0); if (!entityKey) { return null; } const entity = contentState.getEntity(entityKey); const mediaData = entity.getData(); const mediaType = entity.getType(); const handleRemove = () => { onChange === null || onChange === void 0 ? void 0 : onChange(removeBlock(value, block)); }; const mediaProps = { // block: props.block, mediaData, // entityKey, onRemove: handleRemove, editorState: value, contentState: value.getCurrentContent() }; if (mediaType === 'IMAGE') { return (React.createElement(Image, Object.assign({}, mediaProps, { imageEqualRatio: imageEqualRatio, entityKey: entityKey, readOnly: readOnly, block: block, imageResizable: imageResizable, imageControls: imageControls, lock: lock, getContainerNode: getContainerNode, value: value, onChange: onChange, refresh: refresh }))); } if (mediaType === 'AUDIO') { return React.createElement(Audio, Object.assign({}, mediaProps)); } if (mediaType === 'VIDEO') { return React.createElement(Video, Object.assign({}, mediaProps)); } if (mediaType === 'EMBED') { return React.createElement(Embed, Object.assign({}, mediaProps)); } if (mediaType === 'HR') { return React.createElement(HorizontalLine, Object.assign({}, mediaProps)); } if (extendAtomics) { const atomic = extendAtomics.find(item => { return item.type === mediaType; }); if (atomic) { const Component = atomic.component; return React.createElement(Component, Object.assign({}, mediaProps)); } } return null; }; const blockType = block.getType(); const customRenderer = (_a = customBlockRendererFn === null || customBlockRendererFn === void 0 ? void 0 : customBlockRendererFn(block, { editorState: value })) !== null && _a !== void 0 ? _a : null; if (customRenderer) { return customRenderer; } if (blockType === 'atomic') { return { component: renderAtomicBlock, editable: false }; } return null; }; export const getBlockStyleFn = customBlockStyleFn => block => { const blockAlignment = block.getData() && block.getData().get('textAlign'); const blockIndent = block.getData() && block.getData().get('textIndent'); const blockFloat = block.getData() && block.getData().get('float'); const className = [ blockAlignment && cls(`kedao-alignment-${blockAlignment}`), blockIndent && cls(`kedao-text-indent-${blockIndent}`), blockFloat && cls(`kedao-float-${blockFloat}`), customBlockStyleFn === null || customBlockStyleFn === void 0 ? void 0 : customBlockStyleFn(block) ] .filter(Boolean) .join(' '); return className; }; export const getCustomStyleMap = (customStyleMap = {}) => { return Object.assign({ SUPERSCRIPT: { position: 'relative', top: '-8px', fontSize: '11px' }, SUBSCRIPT: { position: 'relative', bottom: '-8px', fontSize: '11px' } }, customStyleMap); }; const getStyleValue = style => style.split('-')[1]; export const getCustomStyleFn = options => (styles, block) => { let output = {}; const { fontFamilies, unitExportFn, customStyleFn } = options; output = customStyleFn ? customStyleFn(styles, block, output) : {}; styles.forEach(style => { if (style.indexOf('COLOR-') === 0) { output.color = `#${getStyleValue(style)}`; } else if (style.indexOf('BGCOLOR-') === 0) { output.backgroundColor = `#${getStyleValue(style)}`; } else if (style.indexOf('FONTSIZE-') === 0) { output.fontSize = unitExportFn(getStyleValue(style), 'font-size', 'editor'); } else if (style.indexOf('LINEHEIGHT-') === 0) { output.lineHeight = unitExportFn(getStyleValue(style), 'line-height', 'editor'); } else if (style.indexOf('LETTERSPACING-') === 0) { output.letterSpacing = unitExportFn(getStyleValue(style), 'letter-spacing', 'editor'); } else if (style.indexOf('TEXTINDENT-') === 0) { output.textIndent = unitExportFn(getStyleValue(style), 'text-indent', 'editor'); } else if (style.indexOf('FONTFAMILY-') === 0) { output.fontFamily = (fontFamilies.find(item => item.name.toUpperCase() === getStyleValue(style)) || {}).family || ''; } }); return output; }; const KEY_SEPARATOR = '-'; CombineDecorators.prototype.getDecorations = function getDecorations(block, contentState) { const decorations = Array(block.getText().length).fill(null); this.decorators.forEach((decorator, i) => { decorator.getDecorations(block, contentState).forEach((key, offset) => { if (!key) { return; } decorations[offset] = i + KEY_SEPARATOR + key; }); }); return Immutable.List(decorations); }; const builtinDecorators = [ { type: 'entity', decorator: { key: 'LINK', component: Link } } ]; const createStrategy = (type) => (block, callback, contentState) => { block.findEntityRanges((character) => { const entityKey = character.getEntity(); return (entityKey !== null && contentState.getEntity(entityKey).getType() === type); }, callback); }; export const getDecorators = () => { return new CombineDecorators([ // combine decorators created with strategy new CompositeDecorator([]), // combine decorators for entities new CompositeDecorator(builtinDecorators.map(item => ({ strategy: createStrategy(item.decorator.key), component: item.decorator.component }))) ]); };