Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.0.0 #41

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions packages/character-count-ui/src/CharacterCounter.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import React, {useEffect} from 'react'
import {Node} from 'slate'
import {toArray} from 'lodash'
import {useStoreEditorRef} from '@udecode/plate-core'
import {useStoreEditorState} from '@udecode/plate-core'
import {TEditor} from '@dreifuss-wysiwyg-editor/common'

const getTextString = (editor: TEditor) => {
Expand All @@ -24,13 +24,14 @@ const calculateCharCount = (editor?: TEditor) => {
return toArray(getTextString(editor)).length
}

export function getCharacterCount(id: string): number {
const editor = useStoreEditorRef(id)
return calculateCharCount(editor)
}
export const CharCountToolbar = ({id, getCharsCount}: {id: string; getCharsCount: any}) => {
const editor = useStoreEditorState(id)

const charCount = calculateCharCount(editor)

export const CharCountToolbar = ({id}: {id: string}) => {
const charCount = getCharacterCount(id)
useEffect(() => {
if (getCharsCount) getCharsCount(charCount)
}, [charCount])

return <span>{charCount}</span>
}
8 changes: 8 additions & 0 deletions packages/common/src/components/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,14 @@ export const ListOLIcon = () => (
</svg>
)

export const CheckBoxIcon = () => (
<svg focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512">
<path
fill="currentColor"
d="M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zm0 400H48V80h352v352zm-35.864-241.724L191.547 361.48c-4.705 4.667-12.303 4.637-16.97-.068l-90.781-91.516c-4.667-4.705-4.637-12.303.069-16.971l22.719-22.536c4.705-4.667 12.303-4.637 16.97.069l59.792 60.277 141.352-140.216c4.705-4.667 12.303-4.637 16.97.068l22.536 22.718c4.667 4.706 4.637 12.304-.068 16.971z"></path>
</svg>
)

export const BorderAllIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentcolor">
<path d="M0 0h24v24H0V0z" fill="none" />
Expand Down
50 changes: 41 additions & 9 deletions packages/common/src/components/modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {ReactNode, useEffect, useRef, useState} from 'react'
import React, {ReactNode, useCallback, useEffect, useRef, useState} from 'react'
import {SubMenuIcon} from '../SubMenuIcon'
import {ModalContext} from './ModalContext'

Expand All @@ -13,39 +13,71 @@ export interface ModalProps {
export const Modal = ({children, Icon, type}: ModalProps) => {
const [isMenuOpen, setIsMenuOpen] = useState(false)

const modalRef = useRef<HTMLDivElement>(null)

const toggleMenu = () => {
setIsMenuOpen(false)
setIsMenuOpen(!isMenuOpen)
}

const modalRef = useRef<HTMLDivElement>(null)

/**
* Add event listener, checks and close modal if what the user is clicking isn't contained within it.
* Add event listener, checks and close modal if
* what the user is clicking isn't contained within it.
*/
useEffect(() => {
function handleClick(e: any) {
if (!modalRef?.current?.contains(e.target)) {
toggleMenu()
setIsMenuOpen(false)
}
}
document.addEventListener('click', handleClick)
return () => document.removeEventListener('click', handleClick)
}, [])

const [position, setPosition] = useState({x: 0, y: 0})

// Reset position if modal is closed and
// position doesn't have initial value
useEffect(() => {
if (!isMenuOpen && (position.x || position.y)) {
setPosition({x: 0, y: 0})
}
}, [isMenuOpen])

// below hooks handling dragging the modal around the window
const modalWindowRef = useRef<HTMLDivElement>(null)

const onMouseDown = useCallback(() => {
const onMouseMove = (event: MouseEvent) => {
position.x += event.movementX
position.y += event.movementY
const element = modalWindowRef.current
if (element) {
element.style.transform = `translate(${position.x}px, ${position.y}px)`
}
setPosition(position)
}
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
}
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
}, [position, setPosition, modalWindowRef])

return (
<ModalContext.Provider
value={{
toggleMenu
}}>
<div className="modal-container" ref={modalRef}>
<div role="presentation" onClick={() => setIsMenuOpen(!isMenuOpen)}>
<div role="presentation" onClick={toggleMenu}>
{type ? <SubMenuIcon type={type} icon={Icon} /> : Icon}
</div>
{isMenuOpen && (
<div className="modal">
<div className="modal" ref={modalWindowRef} onMouseDown={onMouseDown}>
<div>
<div className="close-btn-container">
<div role="presentation" className="close" onClick={() => toggleMenu()}></div>
<div role="presentation" className="close" onClick={toggleMenu}></div>
</div>
</div>
<div style={{flex: '1 1 auto'}}>{children}</div>
Expand Down
9 changes: 0 additions & 9 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,7 @@
"@udecode/plate-autoformat": "^2.0.0",
"@udecode/plate-basic-elements": "^2.0.0",
"@udecode/plate-basic-marks": "^2.0.0",
"@udecode/plate-block-quote": "^2.0.0",
"@udecode/plate-block-quote-ui": "^3.0.1",
"@udecode/plate-break": "^3.0.3",
"@udecode/plate-code-block": "^2.0.0",
"@udecode/plate-code-block-ui": "^3.0.1",
"@udecode/plate-common": "^2.0.0",
"@udecode/plate-core": "^1.0.0",
"@dreifuss-wysiwyg-editor/find-replace": "0.0.0",
Expand All @@ -118,18 +114,13 @@
"@udecode/plate-list": "^3.0.4",
"@udecode/plate-list-ui": "^3.0.4",
"@udecode/plate-md-serializer": "^3.0.5",
"@udecode/plate-media-embed": "^2.0.0",
"@dreifuss-wysiwyg-editor/media-embed-ui": "0.0.0",
"@udecode/plate-mention": "^2.0.0",
"@udecode/plate-mention-ui": "^3.0.1",
"@udecode/plate-styled-components": "^3.0.1",
"@udecode/plate-toolbar": "^3.1.0",
"@udecode/plate-paragraph": "^2.0.0",
"@udecode/plate-select": "^3.4.0",
"@udecode/plate-dnd": "^3.5.1",
"@udecode/plate-node-id": "^4.3.7",
"react-dnd": "^14.0.3",
"react-dnd-html5-backend": "^14.0.1",
"jsx-runtime": "^1.2.0",
"slate": "^0.62.0",
"slate-history": "^0.62.0",
Expand Down
75 changes: 15 additions & 60 deletions packages/core/src/DreifussWysiwygEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import React, {ReactNode, useEffect} from 'react'
import React, {ReactNode} from 'react'
import Divider, {DividerType} from './atoms/Divider'
import {HeadingToolbar} from '@udecode/plate-toolbar'
import {ELEMENT_MEDIA_EMBED} from '@udecode/plate-media-embed'
import {createPlateOptions} from './utils/createPlateOptions'
import {
CharactersCountIcon,
Modal,
ImageIcon,
SearchIcon,
MediaEmbedIcon,
EmojiPicker,
EmojiIcon,
EditorValue
} from '@dreifuss-wysiwyg-editor/common'
import {createPlateComponents} from './utils/createPlateComponents'
import {CharCountToolbar, getCharacterCount} from '@dreifuss-wysiwyg-editor/character-count-ui'
import {CharCountToolbar} from '@dreifuss-wysiwyg-editor/character-count-ui'
import {Plate, TNode, useStoreEditorRef} from '@udecode/plate-core'
import {ToolbarLink} from '@dreifuss-wysiwyg-editor/link-ui'
import {ELEMENT_IMAGE} from '@dreifuss-wysiwyg-editor/image'
Expand All @@ -25,7 +23,6 @@ import {QuotationMarksMenu} from '@dreifuss-wysiwyg-editor/quotation-mark-ui'
import {ELEMENT_QUOTATION_MARK} from '@dreifuss-wysiwyg-editor/quotation-mark'
import {useFindReplacePlugin, MARK_SEARCH_HIGHLIGHT} from '@dreifuss-wysiwyg-editor/find-replace'
import {ToolbarSearchHighlight} from '@dreifuss-wysiwyg-editor/find-replace-ui'
import {MediaEmbedToolbar} from '@dreifuss-wysiwyg-editor/media-embed-ui'
import {
ToolbarLinkButton,
ToolbarBalloon,
Expand All @@ -37,9 +34,6 @@ import {
ToolbarFontBgButton,
ToolbarFontColorButton
} from './Toolbar'
import {DndProvider} from 'react-dnd'
import {HTML5Backend} from 'react-dnd-html5-backend'
import {withStyledDraggables} from './utils/WithStyledDraggables'
import {plugins} from './utils/createPlatePlugins'

export interface EditableProps {
Expand All @@ -55,18 +49,14 @@ export interface Toolbars {
}

export interface EnablePluginsProps {
dnd?: boolean
search?: boolean
list?: boolean
code?: boolean
color?: boolean
bgColor?: boolean
align?: boolean
emoji?: boolean
link?: boolean
image?: boolean
media?: boolean
quote?: boolean
quotationMarks?: boolean
basicMarks?: boolean
basicElements?: boolean
Expand Down Expand Up @@ -94,7 +84,7 @@ const handleOnChange = (value: EditorValue) => {
})
}

function DreifussEditor(props: DreifussWysiwygEditorOptions) {
export default function DreifussWysiwygEditor(props: DreifussWysiwygEditorOptions) {
const defaultOptions: Omit<DreifussWysiwygEditorOptions, 'id'> = {
displayOnly: false,
showCharactersCount: true,
Expand All @@ -110,18 +100,15 @@ function DreifussEditor(props: DreifussWysiwygEditorOptions) {
basicElements: true,
basicMarks: true,
list: true,
quote: true,
quotationMarks: true,
code: false,
color: false,
bgColor: false,
align: true,
table: {tableBorderColor: false, tableBgColor: false},
emoji: false,
link: false,
image: false,
media: false,
search: true,
dnd: false
search: true
}
}

Expand All @@ -143,9 +130,7 @@ function DreifussEditor(props: DreifussWysiwygEditorOptions) {

const {setSearch, plugin: findReplacePlugin} = useFindReplacePlugin()

const components = enablePlugins.dnd
? withStyledDraggables(createPlateComponents(enablePlugins))
: createPlateComponents(enablePlugins)
const components = createPlateComponents(enablePlugins)

const options = createPlateOptions(enablePlugins)

Expand All @@ -165,12 +150,6 @@ function DreifussEditor(props: DreifussWysiwygEditorOptions) {
: {fontFamily: 'Helvetica'}
}

const charCount = getCharacterCount(id)

useEffect(() => {
if (charactersCount) charactersCount(charCount)
}, [charCount])

return (
<div className="dreifuss-wrapper">
<Plate
Expand All @@ -197,12 +176,7 @@ function DreifussEditor(props: DreifussWysiwygEditorOptions) {
</>
)}

{enablePlugins.list && (
<>
<ToolbarListButtons editor={editorRef} />
<Divider type={DividerType.vertical} />
</>
)}
{enablePlugins.list && <ToolbarListButtons editor={editorRef} />}

{enablePlugins.basicMarks && (
<>
Expand All @@ -216,16 +190,14 @@ function DreifussEditor(props: DreifussWysiwygEditorOptions) {
<Modal Icon={<ToolbarFontColorButton editor={editorRef} />}>
<FontColorToolbar type={MARK_COLOR} />
</Modal>
<Divider type={DividerType.vertical} />
</>
)}

{enablePlugins.color && (
{enablePlugins.bgColor && (
<>
<Modal Icon={<ToolbarFontBgButton editor={editorRef} />}>
<FontColorToolbar type={MARK_BG_COLOR} />
</Modal>
<Divider type={DividerType.vertical} />
</>
)}

Expand All @@ -248,7 +220,6 @@ function DreifussEditor(props: DreifussWysiwygEditorOptions) {
<Modal type="EMOJI" Icon={<EmojiIcon />}>
<EmojiPicker />
</Modal>
<Divider type={DividerType.vertical} />
</>
)}

Expand All @@ -257,7 +228,6 @@ function DreifussEditor(props: DreifussWysiwygEditorOptions) {
<Modal Icon={<ToolbarLinkButton editor={editorRef} />}>
<ToolbarLink />
</Modal>
<Divider type={DividerType.vertical} />
</>
)}

Expand All @@ -269,15 +239,6 @@ function DreifussEditor(props: DreifussWysiwygEditorOptions) {
</>
)}

{enablePlugins.media && (
<>
<Modal type={ELEMENT_MEDIA_EMBED} Icon={<MediaEmbedIcon />}>
<MediaEmbedToolbar editorRef={editorRef} />
</Modal>
<Divider type={DividerType.vertical} />
</>
)}

{enablePlugins.search && (
<Modal type={MARK_SEARCH_HIGHLIGHT} Icon={<SearchIcon />}>
<ToolbarSearchHighlight setSearch={setSearch} />
Expand All @@ -287,22 +248,16 @@ function DreifussEditor(props: DreifussWysiwygEditorOptions) {
)}
{showCharactersCount && (
<p style={{display: 'flex', justifyContent: 'right', alignItems: 'center'}}>
<CharactersCountIcon /> <CharCountToolbar id={id} />
<CharactersCountIcon />
<CharCountToolbar
getCharsCount={count => {
if (charactersCount) charactersCount(count)
}}
id={id}
/>
</p>
)}
</Plate>
</div>
)
}

export default function DreifussWysiwygEditor(props: DreifussWysiwygEditorOptions) {
if (props?.enablePlugins?.dnd) {
return (
<DndProvider backend={HTML5Backend}>
<DreifussEditor {...props} />
</DndProvider>
)
}

return <DreifussEditor {...props} />
}
Loading