UNPKG

@amaui/ui-react

Version:
1,129 lines (1,123 loc) 86.4 kB
import _extends from "@babel/runtime/helpers/extends"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; const _excluded = ["tonal", "color", "version", "value", "onChange", "render", "miniMenu", "miniMenuInclude", "exclude", "updates", "actions", "fontFamilies", "addFontFamilies", "IconItalic", "IconUnderline", "IconBold", "IconStrikeLine", "IconColor", "IconBackground", "IconAlignLeft", "IconAlignCenter", "IconAlignRight", "IconAlignJustify", "IconIndent", "IconOutdent", "IconSuperscript", "IconSubscript", "IconListOrdered", "IconListUnordered", "IconHorizontalRule", "IconLinkAdd", "IconLinkRemove", "IconQuote", "IconImage", "IconVideo", "IconVideoYoutube", "IconTable", "IconCode", "IconDrawing", "IconCopy", "IconCut", "IconPaste", "IconDelete", "IconClear", "IconSelectAll", "IconSave", "IconPrint", "IconUndo", "IconRedo", "AppendProps", "ToolbarProps", "ToolbarUpdatesProps", "ToolbarActionsProps", "ToggleButtonProps", "ToggleButtonsProps", "DividerProps", "SelectProps", "ListItemProps", "TooltipProps", "MiniMenuProps", "DrawingProps", "IconProps", "ColorTextFieldProps", "Component", "className", "children"], _excluded2 = ["open", "label", "children"], _excluded3 = ["open", "element", "anchorElement", "onClose", "children"], _excluded4 = ["color"], _excluded5 = ["version", "onUpdate", "onClose"], _excluded6 = ["label", "labelButton", "value", "onChange", "onClick", "InputComponent", "InputProps"]; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } import React from 'react'; import { is, isEnvironment, parse } from '@amaui/utils'; import { classNames, colors, style as styleMethod, useAmauiTheme } from '@amaui/style-react'; import IconMaterialFormatItalic from '@amaui/icons-material-rounded-react/IconMaterialFormatItalicW100'; import IconMaterialFormatUnderlined from '@amaui/icons-material-rounded-react/IconMaterialFormatUnderlinedW100'; import IconMaterialFormatBold from '@amaui/icons-material-rounded-react/IconMaterialFormatBoldW100'; import IconMaterialContentCopy from '@amaui/icons-material-rounded-react/IconMaterialContentCopyW100'; import IconMaterialContentCut from '@amaui/icons-material-rounded-react/IconMaterialContentCutW100'; import IconMaterialContentPaste from '@amaui/icons-material-rounded-react/IconMaterialContentPasteW100'; import IconMaterialFormatAlignLeft from '@amaui/icons-material-rounded-react/IconMaterialFormatAlignLeftW100'; import IconMaterialFormatAlignCenter from '@amaui/icons-material-rounded-react/IconMaterialFormatAlignCenterW100'; import IconMaterialFormatAlignRight from '@amaui/icons-material-rounded-react/IconMaterialFormatAlignRightW100'; import IconMaterialFormatAlignJustify from '@amaui/icons-material-rounded-react/IconMaterialFormatAlignJustifyW100'; import IconMaterialStrikethroughS from '@amaui/icons-material-rounded-react/IconMaterialStrikethroughSW100'; import IconMaterialUndo from '@amaui/icons-material-rounded-react/IconMaterialUndoW100'; import IconMaterialRedo from '@amaui/icons-material-rounded-react/IconMaterialRedoW100'; import IconMaterialFormatClear from '@amaui/icons-material-rounded-react/IconMaterialFormatClearW100'; import IconMaterialSuperscript from '@amaui/icons-material-rounded-react/IconMaterialSuperscriptW100'; import IconMaterialSubscript from '@amaui/icons-material-rounded-react/IconMaterialSubscriptW100'; import IconMaterialFormatIndentIncrease from '@amaui/icons-material-rounded-react/IconMaterialFormatIndentIncreaseW100'; import IconMaterialFormatIndentDecrease from '@amaui/icons-material-rounded-react/IconMaterialFormatIndentDecreaseW100'; import IconMaterialFormatListNumbered from '@amaui/icons-material-rounded-react/IconMaterialFormatListNumberedW100'; import IconMaterialFormatListBulleted from '@amaui/icons-material-rounded-react/IconMaterialFormatListBulletedW100'; import IconMaterialHorizontalRule from '@amaui/icons-material-rounded-react/IconMaterialHorizontalRuleW100'; import IconMaterialFormatColorText from '@amaui/icons-material-rounded-react/IconMaterialFormatColorTextW100'; import IconMaterialFormatColorFill from '@amaui/icons-material-rounded-react/IconMaterialFormatColorFillW100'; import IconMaterialAddLink from '@amaui/icons-material-rounded-react/IconMaterialAddLinkW100'; import IconMaterialLinkOff from '@amaui/icons-material-rounded-react/IconMaterialLinkOffW100'; import IconMaterialImage from '@amaui/icons-material-rounded-react/IconMaterialImageW100'; import IconMaterialFormatQuote from '@amaui/icons-material-rounded-react/IconMaterialFormatQuoteW100'; import IconMaterialVideocam from '@amaui/icons-material-rounded-react/IconMaterialVideocamW100'; import IconMaterialPlayArrow from '@amaui/icons-material-rounded-react/IconMaterialPlayArrowW100'; import IconMaterialCode from '@amaui/icons-material-rounded-react/IconMaterialCodeW100'; import IconMaterialDeleteSweep from '@amaui/icons-material-rounded-react/IconMaterialDeleteSweepW100'; import IconMaterialSelectAll from '@amaui/icons-material-rounded-react/IconMaterialSelectAllW100'; import IconMaterialPrint from '@amaui/icons-material-rounded-react/IconMaterialPrintW100'; import IconMaterialDownload from '@amaui/icons-material-rounded-react/IconMaterialDownloadW100'; import IconMaterialTable from '@amaui/icons-material-rounded-react/IconMaterialTableW100'; import IconMaterialDraw from '@amaui/icons-material-rounded-react/IconMaterialDrawW100'; import TypeElement from '../Type'; import TooltipElement from '../Tooltip'; import FadeElement from '../Fade'; import AppendElement from '../Append'; import SelectElement from '../Select'; import SwitchElement from '../Switch'; import LabelElement from '../Label'; import NumericTextFieldElement from '../NumericTextField'; import ColorTextFieldElement from '../ColorTextField'; import ToggleButtonsElement from '../ToggleButtons'; import ToggleButtonElement from '../ToggleButton'; import DrawingElement from '../Drawing'; import DividerElement from '../Divider'; import ClickListenerElement from '../ClickListener'; import TextFieldElement from '../TextField'; import ButtonElement from '../Button'; import SurfaceElement from '../Surface'; import ListItemElement from '../ListItem'; import LineElement from '../Line'; import { print, save, staticClassName } from '../utils'; const useStyle = styleMethod(theme => ({ root: { width: '100%' }, value: { padding: theme.methods.space.value(2, 'px'), whiteSpace: 'break-spaces', '& p': _objectSpread({}, theme.typography.values.b2), '& h1': _objectSpread({}, theme.typography.values.h1), '& h2': _objectSpread({}, theme.typography.values.h2), '& h3': _objectSpread({}, theme.typography.values.h3), '& h4': _objectSpread({}, theme.typography.values.t1), '& h5': _objectSpread({}, theme.typography.values.t2), '& a': { color: theme.palette.color.primary.main, textDecoration: 'underline' }, '& blockquote': { margin: '16px 0', marginInlineStart: '16px', padding: `${theme.methods.space.value(2.5, 'px')} ${theme.methods.space.value(2, 'px')}`, borderInlineStart: `4px solid ${theme.methods.palette.color.colorToRgb(theme.palette.text.default.primary, theme.palette.light ? 0.04 : 0.2)}`, background: theme.methods.palette.color.colorToRgb(theme.palette.text.default.primary, theme.palette.light ? 0.02 : 0.14), '& > *': { margin: '0px' }, '& > $blockquote': { marginBlock: '16px' } }, '& iframe': { display: 'block', maxWidth: '100%', margin: '16px auto' }, '& video': { display: 'block', margin: '16px auto' }, '& code': { padding: `${theme.methods.space.value(0.25, 'px')} ${theme.methods.space.value(0.5, 'px')}`, borderRadius: theme.methods.shape.radius.value(0.5, 'px'), color: theme.palette.text.default.primary, background: theme.methods.palette.color.colorToRgb(theme.palette.text.default.primary, theme.palette.light ? 0.04 : 0.1) }, '& pre': { margin: '16px 0', padding: theme.methods.space.value(2, 'px'), borderRadius: theme.methods.shape.radius.value(1, 'px'), color: theme.palette.text.default.primary, background: theme.methods.palette.color.colorToRgb(theme.palette.text.default.primary, theme.palette.light ? 0.04 : 0.1), '& code': { padding: '0px', background: 'transparent' } }, '& table': { margin: '16px auto', borderCollapse: 'collapse', border: `1px solid ${theme.palette.light ? theme.palette.color.neutral[80] : theme.palette.color.neutral[30]}`, '& th, & td': _objectSpread(_objectSpread({}, theme.typography.values.b2), {}, { height: '45px', padding: `${theme.methods.space.value(1.5, 'px')} ${theme.methods.space.value(2, 'px')}`, borderBottom: `1px solid ${theme.palette.light ? theme.palette.color.neutral[80] : theme.palette.color.neutral[30]}`, borderRight: `1px solid ${theme.palette.light ? theme.palette.color.neutral[80] : theme.palette.color.neutral[30]}` }), '& th': { fontWeight: 500, borderBottom: `1px solid ${theme.palette.light ? theme.palette.color.neutral[50] : theme.palette.color.neutral[50]}` } }, '& .amaui-Drawing-svg': { display: 'block', margin: '16px auto', background: theme.palette.color.neutral[100] } }, toolbars: { width: '100%' }, toolbar: { width: '100%', overflowX: 'auto', padding: theme.methods.space.value(1, 'px') }, divider: { '&.amaui-Divider-root': { margin: 0 } }, divider_middle: { '&.amaui-Divider-root': { opacity: theme.palette.light ? 0.07 : 0.24 } }, divider_end: { '&.amaui-Divider-root': { opacity: theme.palette.light ? 0.14 : 0.4 } }, select: { '& .amaui-TextField-input-wrapper': { height: '40px', paddingBlock: theme.methods.space.value(1.25, 'px') }, '& .amaui-Select-input': { '& > *': _objectSpread(_objectSpread({}, theme.typography.values.b2), {}, { fontWeight: 400 }) } }, miniMenu: { padding: theme.methods.space.value(1.5, 'px'), borderRadius: theme.methods.shape.radius.value(140, 'px'), boxShadow: theme.shadows.values.default[2] }, palette: { padding: theme.methods.space.value(1.5, 'px'), borderRadius: theme.methods.shape.radius.value(1, 'px'), boxShadow: theme.shadows.values.default[2] }, paletteItem: { position: 'relative', width: '17px', height: '17px', cursor: 'pointer', borderRadius: theme.methods.shape.radius.value(40, 'px'), boxShadow: theme.shadows.values.default[1], transition: theme.methods.transitions.make('box-shadow'), '&:hover': { boxShadow: theme.shadows.values.default[2] } }, textFieldColor: { flex: '1 1 auto' }, inputColor: { border: 'none', borderRadius: theme.methods.shape.radius.value(40, 'px'), overflow: 'hidden', width: '17px', height: '17px', cursor: 'pointer', boxShadow: theme.shadows.values.default[1], '&::-webkit-color-swatch-wrapper': { padding: '0px' }, '&::-webkit-color-swatch': { border: 'none' } } }), { name: 'amaui-RichTextEditor' }); const RichTextEditor = /*#__PURE__*/React.forwardRef((props__, ref) => { const theme = useAmauiTheme(); const props = React.useMemo(() => _objectSpread(_objectSpread(_objectSpread({}, theme?.ui?.elements?.all?.props?.default), theme?.ui?.elements?.amauiRichTextEditor?.props?.default), props__), [props__]); const Line = React.useMemo(() => theme?.elements?.Line || LineElement, [theme]); const Type = React.useMemo(() => theme?.elements?.Type || TypeElement, [theme]); const Tooltip = React.useMemo(() => theme?.elements?.Tooltip || TooltipElement, [theme]); const Fade = React.useMemo(() => theme?.elements?.Fade || FadeElement, [theme]); const Append = React.useMemo(() => theme?.elements?.Append || AppendElement, [theme]); const Select = React.useMemo(() => theme?.elements?.Select || SelectElement, [theme]); const Switch = React.useMemo(() => theme?.elements?.Switch || SwitchElement, [theme]); const Label = React.useMemo(() => theme?.elements?.Label || LabelElement, [theme]); const NumericTextField = React.useMemo(() => theme?.elements?.NumericTextField || NumericTextFieldElement, [theme]); const ColorTextField = React.useMemo(() => theme?.elements?.ColorTextField || ColorTextFieldElement, [theme]); const ToggleButton = React.useMemo(() => theme?.elements?.ToggleButton || ToggleButtonElement, [theme]); const ToggleButtons = React.useMemo(() => theme?.elements?.ToggleButtons || ToggleButtonsElement, [theme]); const Drawing = React.useMemo(() => theme?.elements?.Drawing || DrawingElement, [theme]); const Divider = React.useMemo(() => theme?.elements?.Divider || DividerElement, [theme]); const ClickListener = React.useMemo(() => theme?.elements?.ClickListener || ClickListenerElement, [theme]); const TextField = React.useMemo(() => theme?.elements?.TextField || TextFieldElement, [theme]); const Surface = React.useMemo(() => theme?.elements?.Surface || SurfaceElement, [theme]); const Button = React.useMemo(() => theme?.elements?.Button || ButtonElement, [theme]); const ListItem = React.useMemo(() => theme?.elements?.ListItem || ListItemElement, [theme]); const { tonal = true, color = 'default', version = 'filled', value, onChange, render, miniMenu = true, miniMenuInclude = ['italic', 'underline', 'bold', 'strike-line', 'font-color', 'font-background', 'align-left', 'align-center', 'align-right', 'align-justify', 'link-add', 'link-remove', 'clear'], exclude, updates = true, actions = true, fontFamilies = [{ label: 'Arial', value: `Arial, sans-serif` }, { label: 'Verdana', value: `Verdana, sans-serif` }, { label: 'Helvetica', value: `Helvetica, sans-serif` }, { label: 'Georgia', value: `Georgia, sans-serif` }, { label: 'Roboto', value: `Roboto, sans-serif` }, { label: 'DM Sans', value: `DM Sans, sans-serif` }], addFontFamilies = [], // Update IconItalic = IconMaterialFormatItalic, IconUnderline = IconMaterialFormatUnderlined, IconBold = IconMaterialFormatBold, IconStrikeLine = IconMaterialStrikethroughS, IconColor = IconMaterialFormatColorText, IconBackground = IconMaterialFormatColorFill, IconAlignLeft = IconMaterialFormatAlignLeft, IconAlignCenter = IconMaterialFormatAlignCenter, IconAlignRight = IconMaterialFormatAlignRight, IconAlignJustify = IconMaterialFormatAlignJustify, IconIndent = IconMaterialFormatIndentIncrease, IconOutdent = IconMaterialFormatIndentDecrease, IconSuperscript = IconMaterialSuperscript, IconSubscript = IconMaterialSubscript, IconListOrdered = IconMaterialFormatListNumbered, IconListUnordered = IconMaterialFormatListBulleted, IconHorizontalRule = IconMaterialHorizontalRule, IconLinkAdd = IconMaterialAddLink, IconLinkRemove = IconMaterialLinkOff, IconQuote = IconMaterialFormatQuote, IconImage = IconMaterialImage, IconVideo = IconMaterialVideocam, IconVideoYoutube = IconMaterialPlayArrow, IconTable = IconMaterialTable, IconCode = IconMaterialCode, IconDrawing = IconMaterialDraw, // Action IconCopy = IconMaterialContentCopy, IconCut = IconMaterialContentCut, IconPaste = IconMaterialContentPaste, IconDelete = IconMaterialDeleteSweep, IconClear = IconMaterialFormatClear, IconSelectAll = IconMaterialSelectAll, IconSave = IconMaterialDownload, IconPrint = IconMaterialPrint, IconUndo = IconMaterialUndo, IconRedo = IconMaterialRedo, AppendProps: AppendProps_, ToolbarProps, ToolbarUpdatesProps, ToolbarActionsProps, ToggleButtonProps: ToggleButtonProps_, ToggleButtonsProps: ToggleButtonsProps_, DividerProps: DividerProps_, SelectProps: SelectProps_, ListItemProps: ListItemProps_, TooltipProps: TooltipProps_, MiniMenuProps: MiniMenuProps_, DrawingProps, IconProps: IconProps_, ColorTextFieldProps, Component = 'div', className, children } = props, other = _objectWithoutProperties(props, _excluded); const { classes } = useStyle(); const [inputValues, setInputValues] = React.useState({}); const [open, setOpen] = React.useState({}); const [selected, setSelected] = React.useState([]); const [selection, setSelection] = React.useState(); const refs = { root: React.useRef(undefined), value: React.useRef(undefined), range: React.useRef(undefined), inputValues: React.useRef(undefined), open: React.useRef(undefined), props: React.useRef(undefined), selected: React.useRef(undefined), miniMenu: React.useRef(undefined), miniMenuInclude: React.useRef(undefined), miniMenuElements: { color: React.useRef(undefined), colorPalette: React.useRef(undefined), background: React.useRef(undefined), backgroundPalette: React.useRef(undefined), linkAdd: React.useRef(undefined), linkAddInput: React.useRef(undefined), linkRemove: React.useRef(undefined) }, elements: { color: React.useRef(undefined), background: React.useRef(undefined), linkAdd: React.useRef(undefined), linkRemove: React.useRef(undefined), quote: React.useRef(undefined), image: React.useRef(undefined), video: React.useRef(undefined), videoYoutube: React.useRef(undefined), table: React.useRef(undefined), drawing: React.useRef(undefined), drawingSvg: React.useRef(undefined), drawingSize: React.useRef(undefined), drawingSelect: React.useRef(undefined), drawingPalette: React.useRef(undefined), code: React.useRef(undefined) }, rootDocument: React.useRef(), rootWindow: React.useRef() }; refs.inputValues.current = inputValues; refs.open.current = open; refs.props.current = props; refs.selected.current = selected; refs.miniMenuInclude.current = miniMenuInclude; const rootDocument = isEnvironment('browser') && (refs.root.current?.ownerDocument || window.document); const rootWindow = rootDocument && (rootDocument.defaultView || window); refs.rootDocument.current = rootDocument; refs.rootWindow.current = rootWindow; React.useEffect(() => { // Add value as innerHTML refs.value.current.innerHTML = value; }, [value]); React.useEffect(() => { const selection_ = refs.rootWindow.current.getSelection(); if (selection_.anchorNode && !selection_.anchorNode?.className?.includes('TextField')) refs.range.current = selection_.getRangeAt(0); }, [open]); React.useEffect(() => { if (!selection) { updateOpen('colorMiniMenu', false); updateOpen('backgroundMiniMenu', false); updateOpen('linkMiniMenu', false); } }, [selection]); const query = command => { return parse(refs.rootDocument.current.queryCommandValue(command)); }; const includesMinMenu = function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return args.some(item => refs.miniMenuInclude.current.includes(item)); }; const clear = function () { let element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : refs.value.current; const children_ = Array.from(element.children); const toRemove = []; const other_ = []; children_.forEach((item, index) => { item.tagName === 'SPAN' && !item.innerHTML || item.tagName === 'BR' && index > 0 && children_[index - 1].tagName === 'SPAN' && !children_[index - 1].innerHTML ? toRemove.push(item) : other_.push(item); }); toRemove.forEach(item => item.remove()); other_.forEach(item => clear(item)); }; const onUpdate = event => { // Clear from empty element values clear(); if (is('function', onChange)) onChange(event); }; const updateInputValues = (property, itemValue) => { setInputValues(values => _objectSpread(_objectSpread({}, values), {}, { [property]: itemValue })); }; const updateOpen = (property, itemValue) => { setOpen(values => _objectSpread(_objectSpread({}, values), {}, { [property]: itemValue })); }; const paste = async () => { const value_ = await navigator.clipboard.read(); if (value_) { let values = ''; for (const item of Array.from(value_)) { const valueItem = await item.getType('text/html'); values += await valueItem.text(); } refs.rootDocument.current.execCommand('insertHTML', undefined, values); } }; const method = React.useCallback(command => argument => { switch (command) { // updates case 'italic': refs.rootDocument.current.execCommand('italic'); if (query('italic')) setSelected(values => [...values, 'italic']);else setSelected(values => values.filter(item => item !== 'italic')); break; case 'underline': refs.rootDocument.current.execCommand('underline'); if (query('underline')) setSelected(values => [...values, 'underline']);else setSelected(values => values.filter(item => item !== 'underline')); break; case 'bold': refs.rootDocument.current.execCommand('bold'); if (query('bold')) setSelected(values => [...values, 'bold']);else setSelected(values => values.filter(item => item !== 'bold')); break; case 'strike-line': refs.rootDocument.current.execCommand('strikeThrough'); if (query('strikeThrough')) setSelected(values => [...values, 'strike-line']);else setSelected(values => values.filter(item => item !== 'strike-line')); break; case 'align-left': refs.rootDocument.current.execCommand('justifyLeft'); if (query('justifyLeft')) setSelected(values => [...values.filter(item => !item.includes('align')), 'align-left']);else setSelected(values => values.filter(item => item !== 'align-left')); break; case 'align-center': refs.rootDocument.current.execCommand('justifyCenter'); if (query('justifyCenter')) setSelected(values => [...values.filter(item => !item.includes('align')), 'align-center']);else setSelected(values => values.filter(item => item !== 'align-center')); break; case 'align-right': refs.rootDocument.current.execCommand('justifyRight'); if (query('justifyRight')) setSelected(values => [...values.filter(item => !item.includes('align')), 'align-right']);else setSelected(values => values.filter(item => item !== 'align-right')); break; case 'align-justify': refs.rootDocument.current.execCommand('justifyFull'); if (query('justifyFull')) setSelected(values => [...values.filter(item => !item.includes('align')), 'align-justify']);else setSelected(values => values.filter(item => item !== 'align-justify')); break; case 'superscript': refs.rootDocument.current.execCommand('superscript'); if (query('superscript')) setSelected(values => [...values, 'superscript']);else setSelected(values => values.filter(item => item !== 'superscript')); break; case 'subscript': refs.rootDocument.current.execCommand('subscript'); if (query('subscript')) setSelected(values => [...values, 'subscript']);else setSelected(values => values.filter(item => item !== 'subscript')); break; case 'indent': refs.rootDocument.current.execCommand('indent'); break; case 'outdent': refs.rootDocument.current.execCommand('outdent'); break; case 'font-version': refs.rootDocument.current.execCommand('formatBlock', undefined, argument); break; case 'font-family': refs.rootDocument.current.execCommand('styleWithCSS', true); refs.rootDocument.current.execCommand('fontName', undefined, argument); refs.rootDocument.current.execCommand('styleWithCSS', false); break; case 'font-size': refs.rootDocument.current.execCommand('styleWithCSS', true); refs.rootDocument.current.execCommand('fontSize', undefined, argument); refs.rootDocument.current.execCommand('styleWithCSS', false); break; case 'font-color': refs.rootDocument.current.execCommand('styleWithCSS', true); refs.rootDocument.current.execCommand('foreColor', undefined, argument); refs.rootDocument.current.execCommand('styleWithCSS', false); break; case 'font-background': refs.rootDocument.current.execCommand('styleWithCSS', true); refs.rootDocument.current.execCommand('backColor', undefined, argument); refs.rootDocument.current.execCommand('styleWithCSS', false); break; case 'list-ordered': refs.rootDocument.current.execCommand('insertOrderedList'); if (query('insertOrderedList')) setSelected(values => [...values.filter(item => !item.includes('list')), 'list-ordered']);else setSelected(values => values.filter(item => item !== 'list-ordered')); break; case 'list-unordered': refs.rootDocument.current.execCommand('insertUnorderedList'); if (query('insertUnorderedList')) setSelected(values => [...values.filter(item => !item.includes('list')), 'list-unordered']);else setSelected(values => values.filter(item => item !== 'list-unordered')); break; case 'horizontal-rule': refs.rootDocument.current.execCommand('insertHorizontalRule'); break; case 'link-add': refs.rootDocument.current.execCommand('createLink', undefined, argument); break; case 'link-remove': refs.rootDocument.current.execCommand('unlink'); break; case 'image': refs.rootDocument.current.execCommand('insertImage', undefined, argument); break; case 'html': refs.rootDocument.current.execCommand('insertHTML', undefined, argument); break; // actions case 'copy': refs.rootDocument.current.execCommand('copy'); break; case 'cut': refs.rootDocument.current.execCommand('cut'); break; case 'paste': if (refs.rootDocument.current.queryCommandSupported('paste')) refs.rootDocument.current.execCommand('paste');else paste(); break; case 'delete': refs.rootDocument.current.execCommand('delete'); break; case 'clear': refs.rootDocument.current.execCommand('removeFormat'); break; case 'select-all': refs.rootDocument.current.execCommand('selectAll'); break; case 'undo': refs.rootDocument.current.execCommand('undo'); break; case 'redo': refs.rootDocument.current.execCommand('redo'); break; default: break; } }, []); const includes = function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return !is('array', exclude) || args.some(item => !exclude.includes(item)); }; // italic, underline, bold // updates toolbar const updateOptions = ['font-family', 'font-version', 'font-size', 'font-color', 'font-background', 'italic', 'underline', 'bold', 'strike-line', 'align-left', 'align-center', 'align-right', 'align-justify', 'superscript', 'subscript', 'indent', 'outdent', 'list-ordered', 'list-unordered', 'horizontal-rule', 'link-add', 'link-remove', 'quote', 'image', 'video', 'video-youtube', 'table', 'drawing', 'code']; const updates_ = updates && (!is('array', exclude) || includes(...updateOptions)); // copy, paste, cut // action toolbar const actions_ = actions && (!is('array', exclude) || includes('copy', 'paste', 'cut', 'clear', 'undo', 'redo', 'delete', 'select-all', 'save', 'print')); const AppendProps = _objectSpread({ padding: [14, 14] }, AppendProps_); const DividerProps = _objectSpread({ color: 'inherit' }, DividerProps_); const TooltipProps = _objectSpread({ position: 'bottom', interactive: false }, TooltipProps_); const ToggleButtonsProps = _objectSpread({ tonal, color, version: 'text', border: false }, ToggleButtonsProps_); const ToggleButtonProps = _objectSpread({ size: 'small' }, ToggleButtonProps_); const MiniMenuProps = _objectSpread({ tonal, color: refs.props.current.color !== undefined ? refs.props.current.color : 'themed' }, MiniMenuProps_); const SelectProps = _objectSpread({ tonal, color: refs.props.current.color !== undefined ? refs.props.current.color : 'themed', version: 'outlined', size: 'small', ListProps: { tonal, color: refs.props.current.color !== undefined ? refs.props.current.color : 'themed' }, MenuProps: { portal: true } }, SelectProps_); const ListItemProps = _objectSpread({ size: 'small', PrimaryProps: { style: { fontFamily: 'inherit' } } }, ListItemProps_); const IconProps = _objectSpread({ size: 'small' }, IconProps_); const WrapperToggleButton = React.useCallback( /*#__PURE__*/React.forwardRef((props_, ref_) => { const { open: open_, label, children: children_ } = props_, other_ = _objectWithoutProperties(props_, _excluded2); return /*#__PURE__*/React.createElement(Tooltip, _extends({ open: open_ !== undefined ? open_ : undefined, label: label }, TooltipProps), /*#__PURE__*/React.cloneElement(children_, _objectSpread(_objectSpread({}, other_), children_.props))); }), []); const WrapperAppend = React.useCallback(props_ => { const { open: open_, element, anchorElement, onClose, children: children_ } = props_, other_ = _objectWithoutProperties(props_, _excluded3); return /*#__PURE__*/React.createElement(Append, _extends({ open: open_, element: /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Fade, { in: open_, add: true }, /*#__PURE__*/React.cloneElement(element))), anchorElement: anchorElement, portal: true, alignment: "center", position: "bottom" }, AppendProps), /*#__PURE__*/React.cloneElement(children_, _objectSpread(_objectSpread({}, other_), children_.props))); }, []); const onMouseDown = React.useCallback(() => { const selection_ = refs.rootWindow.current.getSelection(); if (selection_.anchorNode && !selection_.anchorNode?.className?.includes('TextField')) refs.range.current = selection_.getRangeAt(0); }, []); const onMouseUp = React.useCallback(() => { if (refs.range.current) { const selection_ = refs.rootWindow.current.getSelection(); selection_.removeAllRanges(); selection_.addRange(refs.range.current); } }, []); const PaletteItem = React.useCallback(props_ => { const { color: color_ } = props_, other_ = _objectWithoutProperties(props_, _excluded4); return /*#__PURE__*/React.createElement("span", _extends({ className: classNames([staticClassName('RichTextEditor', theme) && ['amaui-RichTextEditor-palette-item'], classes.paletteItem]), style: { background: color_ } }, other_)); }, []); const Palette = React.useCallback( /*#__PURE__*/React.forwardRef((props_, ref_) => { const { version: version_, onUpdate: onUpdate_, onClose } = props_, other_ = _objectWithoutProperties(props_, _excluded5); return /*#__PURE__*/React.createElement(Line, _extends({ ref: ref_, gap: 1, direction: "column", tonal: tonal, color: refs.props.current.color !== undefined ? refs.props.current.color : 'themed', Component: Surface, className: classNames([staticClassName('RichTextEditor', theme) && ['amaui-RichTextEditor-palette'], classes.palette]) }, other_), /*#__PURE__*/React.createElement(Line, { gap: 0.5, onMouseUp: onMouseUp, onMouseDown: onMouseDown }, /*#__PURE__*/React.createElement(Line, { gap: 0.5, direction: "row", style: { width: '100%' } }, /*#__PURE__*/React.createElement(PaletteItem, { color: "#000000", onClick: () => { onUpdate_('#000000'); onClose(); } }), /*#__PURE__*/React.createElement(PaletteItem, { color: "#ffffff", onClick: () => { onUpdate_('#ffffff'); onClose(); } })), Object.keys(colors).filter(item => !['black', 'white'].includes(item)).map((item, index) => /*#__PURE__*/React.createElement(Line, { key: index, gap: 0.5, direction: "row", style: { width: '100%' } }, Object.keys(colors[item]).map((item_, index_) => /*#__PURE__*/React.createElement(PaletteItem, { key: index_, color: colors[item][item_], onClick: () => { if (refs.range.current) { const selection_ = refs.rootWindow.current.getSelection(); selection_.removeAllRanges(); selection_.addRange(refs.range.current); } onUpdate_(colors[item][item_]); onClose(); } }))))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(Line, { gap: 0.5, direction: "row", align: "center", style: { width: '100%' } }, /*#__PURE__*/React.createElement(ColorTextField, _extends({ tonal: tonal, color: color, label: "Custom color", version: "outlined", size: "small", value: refs.inputValues.current[version_], onChange: valueNew => updateInputValues(version_, valueNew) }, ColorTextFieldProps, { className: classNames([staticClassName('RichTextEditor', theme) && ['amaui-RichTextEditor-text-field-color'], ColorTextFieldProps?.className, classes.textFieldColor]) })), /*#__PURE__*/React.createElement(Button, { tonal: tonal, color: "inherit", version: "text", size: "small", onClick: () => { if (refs.range.current) { const selection_ = refs.rootWindow.current.getSelection(); selection_.removeAllRanges(); selection_.addRange(refs.range.current); } onUpdate_(refs.inputValues.current[version_]); onClose(); } }, "Apply"))); }), []); const Input = React.useCallback( /*#__PURE__*/React.forwardRef((props_, ref_) => { const { label, labelButton, value: value__, onChange: onChange__, onClick, InputComponent = TextField, InputProps } = props_, other_ = _objectWithoutProperties(props_, _excluded6); return /*#__PURE__*/React.createElement(Line, _extends({ ref: ref_, gap: 1, direction: "column", tonal: tonal, color: refs.props.current.color !== undefined ? refs.props.current.color : 'themed', Component: Surface, className: classNames([staticClassName('RichTextEditor', theme) && ['amaui-RichTextEditor-palette'], classes.palette]) }, other_), /*#__PURE__*/React.createElement(Line, { gap: 0.5, direction: "row", align: "center", style: { width: '100%' } }, /*#__PURE__*/React.createElement(InputComponent, _extends({ tonal: tonal, color: color, label: label, version: "outlined", size: "small", value: value__, onChange: onChange__, className: classNames([staticClassName('RichTextEditor', theme) && ['amaui-RichTextEditor-text-field-color'], classes.textFieldColor]) }, InputProps)), /*#__PURE__*/React.createElement(Button, { tonal: tonal, color: "inherit", version: "text", size: "small", onClick: onClick }, labelButton))); }), []); const font_families = [...fontFamilies, ...addFontFamilies]; const font_sizes = [{ label: '11', value: 1 }, { label: '14', value: 2 }, { label: '16', value: 3 }, { label: '18', value: 4 }, { label: '24', value: 5 }, { label: '32', value: 6 }, { label: '48', value: 7 }]; const font_versions = [{ label: /*#__PURE__*/React.createElement(Type, { version: "b2" }, "Normal text"), value: 'p' }, { label: /*#__PURE__*/React.createElement(Type, { version: "h1" }, "Heading 1"), value: 'h1' }, { label: /*#__PURE__*/React.createElement(Type, { version: "h2" }, "Heading 2"), value: 'h2' }, { label: /*#__PURE__*/React.createElement(Type, { version: "h3" }, "Heading 3"), value: 'h3' }, { label: /*#__PURE__*/React.createElement(Type, { version: "t1" }, "Heading 4"), value: 'h4' }, { label: /*#__PURE__*/React.createElement(Type, { version: "t2" }, "Heading 5"), value: 'h5' }]; const queryValueUpdate = () => { const selected_ = []; const inputValues_ = _objectSpread({}, inputValues); const updateOptionValues = [{ name: 'italic', command: 'italic' }, { name: 'underline', command: 'underline' }, { name: 'bold', command: 'bold' }, { name: 'strike-line', command: 'strikeThrough' }, { name: 'align-left', command: 'justifyLeft' }, { name: 'align-center', command: 'justifyCenter' }, { name: 'align-right', command: 'justifyRight' }, { name: 'align-justify', command: 'justifyFull' }, { name: 'superscript', command: 'superscript' }, { name: 'subscript', command: 'subscript' }, { name: 'list-ordered', command: 'insertOrderedList' }, { name: 'list-unordered', command: 'insertUnorderedList' }]; updateOptionValues.forEach(item => { if (query(item.command)) selected_.push(item.name); }); // Font version const fontVersion = query('formatBlock'); const fontVersionValue = font_versions.find(item_ => item_.value === fontVersion) || font_versions[0]; inputValues_['font-version'] = fontVersionValue?.value; // Font family const fontFamily = query('fontName'); const fontFamilyValue = font_families.find(item_ => fontFamily?.includes(item_.label)) || font_families.find(item_ => item_.label === 'DM Sans'); inputValues_['font-family'] = fontFamilyValue?.value; // Font version const fontSize = query('fontSize'); const fontSizeValue = font_sizes.find(item_ => item_.value === fontSize) || font_sizes.find(item_ => item_.label === '14'); inputValues_['font-size'] = fontSizeValue?.value; setInputValues(inputValues_); setSelected(selected_); }; const onMouseUpValue = React.useCallback(() => { queryValueUpdate(); setTimeout(() => { const selection_ = refs.rootWindow.current.getSelection(); if (!selection_.anchorNode || !refs.value.current.contains(selection_.anchorNode)) return setSelection(''); const rect = selection_.getRangeAt(0).getBoundingClientRect(); setSelection(Math.round(rect.width) ? rect : ''); }); }, []); const onMouseDownValue = React.useCallback(() => { queryValueUpdate(); }, []); const updateElements = { 'font-version': /*#__PURE__*/React.createElement(Select, _extends({ label: "Font Version", valueDefault: font_versions.find(item => item.value.includes('p')).value, value: inputValues['font-version'], onChange: valueNew => { updateInputValues('font-version', valueNew); method('font-version')(valueNew); }, onMouseUp: onMouseUp, onMouseDown: onMouseDown }, SelectProps, { className: classNames([staticClassName('RichTextEditor', theme) && ['amaui-RichTextEditor-select'], SelectProps?.className, classes.select]), style: { minWidth: '150px' } }), font_versions.map(item => /*#__PURE__*/React.createElement(ListItem, _extends({ key: item.value, primary: item.label, value: item.value, button: true }, ListItemProps)))), 'font-family': /*#__PURE__*/React.createElement(Select, _extends({ label: "Font Family", valueDefault: font_families.find(item => item.label.includes('DM Sans')).value, value: inputValues['font-family'], onChange: valueNew => { updateInputValues('font-family', valueNew); method('font-family')(valueNew); }, onMouseUp: onMouseUp, onMouseDown: onMouseDown }, SelectProps, { className: classNames([staticClassName('RichTextEditor', theme) && ['amaui-RichTextEditor-select'], SelectProps?.className, classes.select]), style: { minWidth: '140px' } }), font_families.map(item => /*#__PURE__*/React.createElement(ListItem, _extends({ key: item.value, primary: item.label, value: item.value, button: true, style: { fontFamily: item.value } }, ListItemProps)))), 'font-size': /*#__PURE__*/React.createElement(Select, _extends({ label: "Font Size", valueDefault: +font_sizes.find(item => item.label.includes('14')).value, value: inputValues['font-size'], onChange: valueNew => { updateInputValues('font-size', +valueNew); method('font-size')(+valueNew); }, onMouseUp: onMouseUp, onMouseDown: onMouseDown }, SelectProps, { className: classNames([staticClassName('RichTextEditor', theme) && ['amaui-RichTextEditor-select'], SelectProps?.className, classes.select]) }), font_sizes.map(item => /*#__PURE__*/React.createElement(ListItem, _extends({ key: item.value, primary: item.label, value: item.value, button: true }, ListItemProps)))), 'italic': /*#__PURE__*/React.createElement(WrapperToggleButton, { label: "Italic" }, is('function', render) ? render('italic', ToggleButtonProps, refs.value.current, method) : /*#__PURE__*/React.createElement(ToggleButton, _extends({}, ToggleButtonProps, { selected: refs.selected.current.includes('italic'), onClick: method('italic') }), /*#__PURE__*/React.createElement(IconItalic, IconProps))), 'underline': /*#__PURE__*/React.createElement(WrapperToggleButton, { label: "Underline" }, is('function', render) ? render('underline', ToggleButtonProps, refs.value.current, method) : /*#__PURE__*/React.createElement(ToggleButton, _extends({}, ToggleButtonProps, { selected: refs.selected.current.includes('underline'), onClick: method('underline') }), /*#__PURE__*/React.createElement(IconUnderline, IconProps))), 'bold': /*#__PURE__*/React.createElement(WrapperToggleButton, { label: "Bold", onClick: method('bold') }, is('function', render) ? render('bold', ToggleButtonProps, refs.value.current, method) : /*#__PURE__*/React.createElement(ToggleButton, _extends({}, ToggleButtonProps, { selected: refs.selected.current.includes('bold') }), /*#__PURE__*/React.createElement(IconBold, IconProps))), 'strike-line': /*#__PURE__*/React.createElement(WrapperToggleButton, { label: "Strike Line", onClick: method('strike-line') }, is('function', render) ? render('strike-line', ToggleButtonProps, refs.value.current, method) : /*#__PURE__*/React.createElement(ToggleButton, _extends({}, ToggleButtonProps, { selected: refs.selected.current.includes('strike-line') }), /*#__PURE__*/React.createElement(IconStrikeLine, IconProps))), 'font-color': /*#__PURE__*/React.createElement(WrapperAppend, { open: refs.open.current.color, anchorElement: refs.elements.color.current, element: /*#__PURE__*/React.createElement(ClickListener, { onClickOutside: () => updateOpen('color', false), include: [refs.elements.color.current] }, /*#__PURE__*/React.createElement(Palette, { version: "font-color", onClose: () => updateOpen('color', false), onUpdate: method('font-color') })) }, /*#__PURE__*/React.createElement(WrapperToggleButton, { label: "Text Color", open: refs.open.current.color ? false : undefined }, is('function', render) ? render('font-color', ToggleButtonProps, refs.value.current, method) : /*#__PURE__*/React.createElement(ToggleButton, _extends({ ref: refs.elements.color }, ToggleButtonProps, { selected: refs.open.current.color, onClick: () => updateOpen('color', !refs.open.current.color) }), /*#__PURE__*/React.createElement(IconColor, IconProps)))), 'font-color-mini-menu': /*#__PURE__*/React.createElement(WrapperAppend, { open: refs.open.current.colorMiniMenu, anchorElement: refs.miniMenuElements.color, element: /*#__PURE__*/React.createElement(ClickListener, { onClickOutside: () => updateOpen('colorMiniMenu', false), include: [refs.miniMenuElements.color] }, /*#__PURE__*/React.createElement(Palette, { ref: refs.miniMenuElements.colorPalette, version: "font-color", onClose: () => updateOpen('colorMiniMenu', false), onUpdate: method('font-color') })) }, /*#__PURE__*/React.createElement(WrapperToggleButton, { label: "Text Color", open: refs.open.current.colorMiniMenu ? false : undefined }, is('function', render) ? render('font-color', ToggleButtonProps, refs.value.current, method) : /*#__PURE__*/React.createElement(ToggleButton, _extends({ ref: refs.miniMenuElements.color }, ToggleButtonProps, { selected: refs.open.current.colorMiniMenu, onClick: () => updateOpen('colorMiniMenu', !refs.open.current.colorMiniMenu) }), /*#__PURE__*/React.createElement(IconColor, IconProps)))), 'font-background': /*#__PURE__*/React.createElement(WrapperAppend, { open: refs.open.current.background, anchorElement: refs.elements.background.current, element: /*#__PURE__*/React.createElement(ClickListener, { onClickOutside: () => updateOpen('background', false), include: [refs.elements.background.current] }, /*#__PURE__*/React.createElement(Palette, { version: "font-background", onClose: () => updateOpen('background', false), onUpdate: method('font-background') })) }, /*#__PURE__*/React.createElement(WrapperToggleButton, { label: "Background Color", open: refs.open.current.background ? false : undefined }, is('function', render) ? render('font-background', ToggleButtonProps, refs.value.current, method) : /*#__PURE__*/React.createElement(ToggleButton, _extends({ ref: refs.elements.background }, ToggleButtonProps, { selected: refs.open.current.background, onClick: () => updateOpen('background', !refs.open.current.background) }), /*#__PURE__*/React.createElement(IconBackground, IconProps)))), 'font-background-mini-menu': /*#__PURE__*/React.createElement(WrapperAppend, { open: refs.open.current.backgroundMiniMenu, anchorElement: refs.miniMenuElements.background, element: /*#__PURE__*/React.createElement(ClickListener, { onClickOutside: () => updateOpen('backgroundMiniMenu', false), include: [refs.miniMenuElements.background] }, /*#__PURE__*/React.createElement(Palette, { ref: refs.miniMenuElements.backgroundPalette, version: "font-background", onClose: () => updateOpen('backgroundMiniMenu', false), onUpdate: method('font-background') })) }, /*#__PURE__*/React.createElement(WrapperToggleButton, { label: "Text Color", open: refs.open.current.backgroundMiniMenu ? false : undefined }, is('function', render) ? render('font-background', ToggleButtonProps, refs.value.current, method) : /*#__PURE__*/React.createElement(ToggleButton, _extends({ ref: refs.miniMenuElements.background }, ToggleButtonProps, { selected: refs.open.current.backgroundMiniMenu, onClick: () => updateOpen('backgroundMiniMenu', !refs.open.current.backgroundMiniMenu) }), /*#__PURE__*/React.createElement(IconBackground, IconProps)))), 'align-left': /*#__PURE__*/React.createElement(WrapperToggleButton, { label: "Align Left" }, is('function', render) ? render('align-left', ToggleButtonProps, refs.value.current, method) : /*#__PURE__*/React.createElement(ToggleButton, _extends({}, ToggleButtonProps, { selected: refs.selected.current.includes('align-left'), onClick: method('align-left') }), /*#__PURE__*/React.createElement(IconAlignLeft, IconP