diff --git a/wax-prosemirror-components/src/components/EditorInfo/CounterInfo/EditorInfoTool.js b/wax-prosemirror-components/src/components/EditorInfo/CounterInfo/EditorInfoTool.js index 4912f0a42410e067fa45007f77505e3340bba41a..c5b07334f5e069b3c64d313499cb5d695966316e 100644 --- a/wax-prosemirror-components/src/components/EditorInfo/CounterInfo/EditorInfoTool.js +++ b/wax-prosemirror-components/src/components/EditorInfo/CounterInfo/EditorInfoTool.js @@ -1,17 +1,46 @@ -import React, { useMemo, useState, useRef, useContext, useEffect, useCallback } from 'react'; +import React, { + useMemo, + useState, + useRef, + useContext, + useEffect, + useCallback, +} from 'react'; import styled from 'styled-components'; -import { grid } from '@pubsweet/ui-toolkit'; +import { grid, th } from '@pubsweet/ui-toolkit'; import { v4 as uuidv4 } from 'uuid'; import { WaxContext } from 'wax-prosemirror-core'; import { DocumentHelpers } from 'wax-prosemirror-utilities'; import MenuButton from '../../../ui/buttons/MenuButton'; import useOnClickOutside from '../../../helpers/useOnClickOutside'; - const Wrapper = styled.div` font-size: 0; position: relative; z-index: 2; + + button { + border: ${props => + props.active ? `1px solid #535E76` : `1px solid #D8DAE0`}; + + &:hover { + background: ${props => (props.active ? `#535E76` : '#D8DAE0')}; + } + } + + &:before { + border-bottom: ${props => + props.active ? `8px solid #535E76` : `8px solid #D8DAE0`}; + + border-left: 8px solid transparent; + border-right: 8px solid transparent; + bottom: 26px; + content: ''; + height: 0; + left: 48%; + position: relative; + width: 0; + } `; const DropWrapper = styled.div` @@ -22,21 +51,20 @@ const DropWrapper = styled.div` width: max-content; `; const CounterInfoComponent = styled.div` - background:white; - border:1px solid gray; - bottom:45px; + background: white; + border: 1px solid ${th('colorPrimary')}; + bottom: 45px; display: flex; flex-direction: column; - position:fixed; - right:50px; + position: fixed; + right: 31px; `; const Counter = styled.div` - color:black; - cursor: pointer; + color: black; display: block; - font-size:14px; + font-size: 14px; height: 25px; - margin:5px; + margin: 5px; min-width: 150px; `; @@ -53,17 +81,19 @@ const EditorInfoTool = ({ view: { state }, item }) => { const [footnoteCount, setFootNoteCount] = useState(); const [blocklevelNode, setBlockLevelNodes] = useState(); const ref = useRef(); - const {activeView,view: { main } } = useContext(WaxContext); + const { + activeView, + view: { main }, + } = useContext(WaxContext); const allBlockNodes = DocumentHelpers.findBlockNodes(main.state.doc); const InlineNodes = DocumentHelpers.findInlineNodes(main.state.doc); useOnClickOutside(ref, () => setIsOpen(false)); - const infoDropDownOptions = [ { name: `${getWordCountFromState} Words` }, { name: `${totalCharCount} Characters` }, - { name: `${totalCharCountWithoutSpace} Character Without Space` }, + { name: `${totalCharCountWithoutSpace} Characters Without Space` }, { name: `${paraCount} Paragraph` }, { name: `${imgCount} Images` }, { name: `${tableCount} Tables` }, @@ -74,11 +104,11 @@ const EditorInfoTool = ({ view: { state }, item }) => { const renderList = () => { const lists = []; - Object.keys(infoDropDownOptions).forEach(key=>{ + Object.keys(infoDropDownOptions).forEach(key => { lists.push( - <Counter key={uuidv4()} - title={infoDropDownOptions[key].name}><span>{infoDropDownOptions[key].name}</span> - </Counter> + <Counter key={uuidv4()} title={infoDropDownOptions[key].name}> + <span>{infoDropDownOptions[key].name}</span> + </Counter>, ); }); return <div>{lists}</div>; @@ -87,16 +117,19 @@ const EditorInfoTool = ({ view: { state }, item }) => { let getWordCountFromStates = 0; InlineNodes.forEach(value => { if (value.node.text !== undefined && value.node.text.length > 0) { - value.node.text.trim().split(" ").forEach((key, pos) => { - if (key.length > 0) { - getWordCountFromStates += 1; - } - }) + value.node.text + .trim() + .split(' ') + .forEach((key, pos) => { + if (key.length > 0) { + getWordCountFromStates += 1; + } + }); } - }) - return getWordCountFromStates + }); + return getWordCountFromStates; }); - + const getCharCount = useCallback(() => { let totalCharCounts = 0; @@ -104,7 +137,7 @@ const EditorInfoTool = ({ view: { state }, item }) => { if (value.node.text !== undefined) { totalCharCounts += value.node.text.length; } - }) + }); return totalCharCounts; }); @@ -112,9 +145,10 @@ const EditorInfoTool = ({ view: { state }, item }) => { let totalCharCountWithoutSpaces = 0; InlineNodes.forEach(value => { if (value.node.text !== undefined) { - totalCharCountWithoutSpaces += value.node.text.replace(/\s+/g, '').length; + totalCharCountWithoutSpaces += value.node.text.replace(/\s+/g, '') + .length; } - }) + }); return totalCharCountWithoutSpaces; }); @@ -129,45 +163,43 @@ const EditorInfoTool = ({ view: { state }, item }) => { allBlockNodes.forEach(value => { if (value.pos === 0) { blockLevelCount = 0; - } - else { + } else { blockLevelCount = allBlockNodes.length; } - }) + }); setBlockLevelNodes(blockLevelCount); allBlockNodes.forEach(value => { value.node.forEach(imgs => { - if (imgs.type.name === "image") { + if (imgs.type.name === 'image') { imgCounts += 1; } - if (imgs.type.name === "footnote") { + if (imgs.type.name === 'footnote') { footNoteCount += 1; } - }) - - }) + }); + }); main.state.doc.content.content.forEach(value => { - if (value.attrs.class === "paragraph" && value.content.size > 0) { + if (value.attrs.class === 'paragraph' && value.content.size > 0) { paraCounts += 1; } - if (value.type.name === "table") { + if (value.type.name === 'table') { tableCounts += 1; } value.content.content.forEach(listTable => { listTable.content.content.forEach(lastListTable => { - if (lastListTable.type.name === "table") { - listTableCount += 1 + if (lastListTable.type.name === 'table') { + listTableCount += 1; } lastListTable.content.content.forEach(nestedTable => { nestedTable.content.content.forEach(nestedTypeTable => { - if (nestedTypeTable.type.name === "table") { + if (nestedTypeTable.type.name === 'table') { nestTableCount += 1; } - }) - }) - }) - }) - }) + }); + }); + }); + }); + }); setImgCount(imgCounts); setTotalParagraph(paraCounts); setTableCount(tableCounts + listTableCount + nestTableCount); @@ -183,16 +215,19 @@ const EditorInfoTool = ({ view: { state }, item }) => { let selectedListTableCount = 0; let finalNestedValueCount = 0; state.selection.content().content.content.forEach(value => { - value.content.content.forEach((textValue) => { + value.content.content.forEach(textValue => { if (textValue.text) { - const textArray = textValue.text.trim().split(" "); + const textArray = textValue.text.trim().split(' '); let isChar = false; textArray.forEach((key, pos) => { // eslint-disable-next-line no-restricted-globals - if (key.charCodeAt(pos) !== 32 && isNaN(key.charCodeAt(pos))===false) { + if ( + key.charCodeAt(pos) !== 32 && + isNaN(key.charCodeAt(pos)) === false + ) { isChar = true; } - }) + }); if (isChar) { selectedCountPara += textValue.text.trim().split(' ').length; } @@ -205,7 +240,7 @@ const EditorInfoTool = ({ view: { state }, item }) => { if (key.charCodeAt(pos) !== 32) { isFootChar = true; } - }) + }); if (isFootChar) { footNodeCount += listValue.text.trim().split(' ').length; } @@ -216,10 +251,13 @@ const EditorInfoTool = ({ view: { state }, item }) => { let isItemChar = false; itemArray.forEach((key, pos) => { // eslint-disable-next-line no-restricted-globals - if (key.charCodeAt(pos) !== 32 && isNaN(key.charCodeAt(pos))===false) { + if ( + key.charCodeAt(pos) !== 32 && + isNaN(key.charCodeAt(pos)) === false + ) { isItemChar = true; } - }) + }); if (isItemChar) { selectedCountList += listItem.text.trim().split(' ').length; } @@ -227,104 +265,147 @@ const EditorInfoTool = ({ view: { state }, item }) => { listItem.content.content.forEach(nestedItem => { nestedItem.content.content.forEach(nestIn => { if (nestIn.text !== undefined) { - const nestArray = nestIn.text.trim().split(" "); + const nestArray = nestIn.text.trim().split(' '); let isNestChar = false; nestArray.forEach((key, pos) => { // eslint-disable-next-line no-restricted-globals - if (key.charCodeAt(pos) !== 32 && isNaN(key.charCodeAt(pos))===false) { + if ( + key.charCodeAt(pos) !== 32 && + isNaN(key.charCodeAt(pos)) === false + ) { isNestChar = true; } - }) + }); if (nestIn.text && isNestChar) { selectedCountNest += nestIn.text.trim().split(' ').length; } } - + nestIn.content.content.forEach(listTable => { if (listTable.text !== undefined) { const listTableArray = listTable.text.trim().split(' '); let isListChar = false; listTableArray.forEach((key, pos) => { // eslint-disable-next-line no-restricted-globals - if (key.charCodeAt(pos) !== 32 && isNaN(key.charCodeAt(pos))===false) { + if ( + key.charCodeAt(pos) !== 32 && + isNaN(key.charCodeAt(pos)) === false + ) { isListChar = true; } - }) + }); if (listTable.text && isListChar) { - selectedListTableCount += listTable.text.trim().split(' ').length + selectedListTableCount += listTable.text.trim().split(' ') + .length; } } - listTable.content.content.forEach(tableValue => { tableValue.content.content.forEach(finalTableValue => { if (finalTableValue.text !== undefined) { - const finalTableArray = finalTableValue.text.trim().split(" ") + const finalTableArray = finalTableValue.text + .trim() + .split(' '); let isFinalTable = false; finalTableArray.forEach((key, pos) => { // eslint-disable-next-line no-restricted-globals - if (key.charCodeAt(pos) !== 32 && isNaN(key.charCodeAt(pos))===false) { + if ( + key.charCodeAt(pos) !== 32 && + isNaN(key.charCodeAt(pos)) === false + ) { isFinalTable = true; } - }) + }); if (finalNestedValueCount.text && isFinalTable) { - finalNestedValueCount = finalTableValue.text.trim().split(" ").length + finalNestedValueCount = finalTableValue.text + .trim() + .split(' ').length; } } - }) - }) - }) - }) - }) - }) - }) - }) + }); + }); + }); + }); + }); + }); + }); + }); if (value.text !== undefined) { - const valueArray = value.text.trim().split(" "); + const valueArray = value.text.trim().split(' '); let isValue = false; valueArray.forEach((key, pos) => { // eslint-disable-next-line no-restricted-globals - if (key.charCodeAt(pos) !== 32 && isNaN(key.charCodeAt(pos))===false) { + if ( + key.charCodeAt(pos) !== 32 && + isNaN(key.charCodeAt(pos)) === false + ) { isValue = true; } - }) + }); if (isValue) { - noteTextValue += value.text.trim().split(" ").length; + noteTextValue += value.text.trim().split(' ').length; } } }); - setSelectedTextCount(selectedCountNest + finalNestedValueCount + selectedListTableCount + selectedCountPara + selectedCountList + noteTextValue + footNodeCount) - if (activeView.state.selection.$from.pos === activeView.state.selection.$to.pos) { + setSelectedTextCount( + selectedCountNest + + finalNestedValueCount + + selectedListTableCount + + selectedCountPara + + selectedCountList + + noteTextValue + + footNodeCount, + ); + if ( + activeView.state.selection.$from.pos === + activeView.state.selection.$to.pos + ) { setSelectedTextCount(0); } - }) + }); const MenuButtonComponent = useMemo( () => ( - <Wrapper ref={ref}> - + <Wrapper active={isOpen} ref={ref}> <MenuButton active={isOpen} disabled={false} - label={`${getSelectionCountFromState >0 ? getSelectionCountFromState : getWordCountFromState} - word${getSelectionCountFromState && getSelectionCountFromState > 1 ? 's' : ''}${!getSelectionCountFromState && getWordCountFromState > 1 ? 's' : ''}`} - onMouseDown={() => setIsOpen(true)} + label={`${ + getSelectionCountFromState > 0 + ? getSelectionCountFromState + : getWordCountFromState + } + word${ + getSelectionCountFromState && getSelectionCountFromState > 1 + ? 's' + : '' + }${ + !getSelectionCountFromState && getWordCountFromState > 1 ? 's' : '' + }`} + onMouseDown={() => { + setIsOpen(!isOpen); + }} title={title} /> {isOpen && ( <DropWrapper> - <CounterInfoComponent key={uuidv4()} item={item} view={state} + <CounterInfoComponent close={() => { setIsOpen(false); - }}>{renderList()}</CounterInfoComponent> + }} + item={item} + key={uuidv4()} + view={state} + > + {renderList()} + </CounterInfoComponent> </DropWrapper> )} </Wrapper> ), [isOpen, getWordCountFromState, getSelectionCountFromState], ); - return MenuButtonComponent + return MenuButtonComponent; }; export default EditorInfoTool; - diff --git a/wax-prosemirror-components/src/icons/icons.js b/wax-prosemirror-components/src/icons/icons.js index a60be4db4bca986de2bc5d7def06d27212271fbe..f7246072053b1fbfbcfaef53eea21d9d97459e2b 100644 --- a/wax-prosemirror-components/src/icons/icons.js +++ b/wax-prosemirror-components/src/icons/icons.js @@ -200,6 +200,12 @@ export default { <path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" /> </Svg> ), + arrowDown: ({ className }) => ( + <Svg className={className} viewBox="0 0 24 24"> + <path d="M0 0h24v24H0V0z" fill="none" /> + <path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z" /> + </Svg> + ), codeBlock: ({ className }) => ( <Svg className={className}