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

Replace slate-plugins with its successor, plate #841

Merged
merged 20 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
73cd1ff
Remove eslint deps, upgrade to the last 1.x apollo gql codegen package.
Lanny Mar 18, 2023
914b8b4
Well we can load the editor I guess?
Lanny Mar 19, 2023
da6bb6f
Got tables rendering, toolbar stuff for tables is still borked though.
Lanny Apr 5, 2023
9695274
Flagrant abuse of the typesystem.
Lanny Apr 11, 2023
4bed84a
Well, we're installable with this package-lock config, but not
Lanny Apr 11, 2023
ecba6eb
Merge branch 'master' of github.com:Journaly/journaly into plate-woo
Lanny Apr 11, 2023
cbcb91e
Maybe bumping the node version in CI will get us peer deps installed?
Lanny Apr 11, 2023
1476e3d
Update package-lock.json
robin-macpherson Apr 19, 2023
5fe0488
Fix issue with translations no loading after next upgrade
Lanny Apr 26, 2023
280bbc9
Fix memorization onKeyDown memoization hanging onto a stale value and…
Lanny Apr 26, 2023
096b7b0
Fix issue where state of editor wouldn't be run through `setValue`.
Lanny Apr 26, 2023
43f2a05
Fix serialization of table elements, honor plate's resizable table at…
Lanny Apr 26, 2023
e851d0a
Merge branch 'plate-woo' of github.com:Journaly/journaly into plate-woo
Lanny May 2, 2023
347b144
Merge branch 'master' of github.com:Journaly/journaly into plate-woo
Lanny May 2, 2023
1b5807e
Bump prisma and prisma/client deps to 3.15.2
Lanny May 2, 2023
cb7d6f2
Upgrade j-db-client version in web to use new prisma version.
Lanny May 2, 2023
abe98e3
Fix un-auth'd nav not getting appropriate styling.
Lanny May 2, 2023
4d6a008
Fix style regression on feature tables.
Lanny May 2, 2023
98b9cd8
Update serverless translation resolution process.
Lanny May 3, 2023
b89b0bc
Try a different translation resolution strategy during SSR. Just thro…
Lanny May 3, 2023
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
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ jobs:
steps:
- checkout
- node/install:
node-version: 14.17.4
npm-version: 6.14.14
node-version: 16.17.0
npm-version: 8.15.0
- restore_cache:
keys:
- node-deps-v3-{{ checksum "packages/web/package-lock.json" }}
Expand Down
135 changes: 92 additions & 43 deletions packages/web/components/JournalyEditor/JournalyEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import React, { useEffect, useMemo, useCallback } from 'react'
import { createEditor, Editor, Descendant } from 'slate'
import { Slate, withReact } from 'slate-react'
import { withHistory } from 'slate-history'
import { pipe, TablePlugin, EditablePlugins } from '@udecode/slate-plugins'
import { Editor } from 'slate'
import {
createPlateEditor,
Plate,
PlateProvider,
PlateEditor,
TElement,
createPlugins,
createTablePlugin,
createPlateUI,
} from '@udecode/plate'
import isHotkey from 'is-hotkey'

import theme from '@/theme'
import PostBodyStyles from '@/components/PostBodyStyles'
import Toolbar from './Toolbar'
import RenderElement from './RenderElement'
import RenderLeaf from './RenderLeaf'
import { withLinks, withImages, toggleMark, options, MarkType } from './helpers'
import { withLinks, withImages, toggleMark, MarkType } from './helpers'
import usePlayPolyphonicSound from '@/hooks/usePlayPolyphonicSound'
import useAutosavedState from '@/hooks/useAutosavedState'

Expand Down Expand Up @@ -46,14 +53,12 @@ const KEY_BLACK_LIST = new Set([
])

type JournalyEditorProps = {
value: Descendant[]
setValue: (value: Descendant[]) => void
value: TElement[]
setValue: (value: TElement[]) => void
slateRef: React.RefObject<Editor>
allowInlineImages: boolean
disabled?: boolean
}
const plugins = [TablePlugin(options)]

const JournalyEditor = ({
value,
setValue,
Expand All @@ -63,16 +68,25 @@ const JournalyEditor = ({
}: JournalyEditorProps) => {
const renderElement = useCallback((props) => <RenderElement {...props} />, [])
const renderLeaf = useCallback((props) => <RenderLeaf {...props} />, [])
const editor = useMemo(() => {
const withPlugins: ((ed: Editor) => Editor)[] = [withHistory, withLinks]

if (allowInlineImages) {
withPlugins.push(withImages)
}
const plugins = useMemo(() => {
return createPlugins(
[ createTablePlugin({}) ],
{
components: createPlateUI()
}
)
}, [])

const editor = useMemo(() => {
const editor = withLinks(createPlateEditor({
plugins: plugins as any
}) as Editor)

return pipe(withReact(createEditor()), ...withPlugins)
return allowInlineImages ? withImages(editor) : editor
}, [])


const [shouldPlayTypewriterSounds, setShouldPlayTypewriterSounds] = useAutosavedState(false, {
key: 'shouldPlayTypewriterSounds',
})
Expand All @@ -83,16 +97,24 @@ const JournalyEditor = ({
1,
)

const handlePlayTypewriterSound = (e: React.KeyboardEvent) => {
const onKeyDown = useCallback((event: React.KeyboardEvent) => {
if (shouldPlayTypewriterSounds) {
if (KEY_BLACK_LIST.has(e.key)) return
else if (e.key === 'Enter') {
if (KEY_BLACK_LIST.has(event.key)) return
else if (event.key === 'Enter') {
playTypewriterReturnSound()
} else {
playTypewriterSound()
}
}
}

Object.entries(HOTKEYS).forEach(([hotkey, mark]) => {
// Convert React keyboard event to native keyboard event
if (isHotkey(hotkey, event as unknown as KeyboardEvent)) {
event.preventDefault()
toggleMark(editor, mark)
}
})
}, [editor, playTypewriterSound, playTypewriterReturnSound])

useEffect(() => {
;(slateRef as React.MutableRefObject<Editor>).current = editor
Expand All @@ -105,6 +127,56 @@ const JournalyEditor = ({
return (
<div className="editor-wrapper">
<div className="editor-container">
<PlateProvider editor={editor as PlateEditor}>
<Plate
value={value}
onChange={(v) => setValue(v)}
editableProps={{
spellCheck: true,
readOnly: disabled,
onKeyDown: onKeyDown,
renderElement,
renderLeaf,
}}
firstChildren={(
<Toolbar
allowInlineImages={allowInlineImages}
shouldPlayTypewriterSounds={shouldPlayTypewriterSounds}
onToggleShouldPlayTypewriterSounds={() =>
setShouldPlayTypewriterSounds(!shouldPlayTypewriterSounds)
}
/>
)}
/>
</PlateProvider>
</div>
<PostBodyStyles parentClassName="editor-container" />
<style jsx>{`
.editor-container {
display: flex;
flex-direction: column;

padding: 0 25px 10px;
border: 1px solid ${theme.colors.black};
border-radius: 5px;
background-color: ${theme.colors.white};
opacity: ${disabled ? 0.6 : 'auto'};
min-height: 200px;
}

.editor-container > :global([contenteditable='true']) {
flex: 1;
padding-top: 15px;
}
`}</style>
</div>
)
}

export default JournalyEditor


/*
robin-macpherson marked this conversation as resolved.
Show resolved Hide resolved
<Slate editor={editor} value={value} onChange={(value) => setValue(value)}>
<Toolbar
allowInlineImages={allowInlineImages}
Expand Down Expand Up @@ -135,28 +207,5 @@ const JournalyEditor = ({
data-testid="post-body"
/>
</Slate>
</div>
<PostBodyStyles parentClassName="editor-container" />
<style jsx>{`
.editor-container {
display: flex;
flex-direction: column;

padding: 0 25px 10px;
border: 1px solid ${theme.colors.black};
border-radius: 5px;
background-color: ${theme.colors.white};
opacity: ${disabled ? 0.6 : 'auto'};
min-height: 200px;
}

.editor-container > :global([contenteditable='true']) {
flex: 1;
padding-top: 15px;
}
`}</style>
</div>
)
}

export default JournalyEditor
*/
11 changes: 2 additions & 9 deletions packages/web/components/JournalyEditor/RenderElement.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react'
import { renderElementTable } from '@udecode/slate-plugins'
//import { renderElementTable } from '@udecode/plate'
robin-macpherson marked this conversation as resolved.
Show resolved Hide resolved
import { useSelected, RenderElementProps } from 'slate-react'

import { isImageNode, isLinkNode, isTableFamilyNode } from '@/utils/slate'
import { isImageNode, isLinkNode } from '@/utils/slate'

const ImageElement = ({ attributes, element, children }: RenderElementProps) => {
const selected = useSelected()
Expand All @@ -25,13 +25,6 @@ const ImageElement = ({ attributes, element, children }: RenderElementProps) =>
const RenderElement = (props: RenderElementProps) => {
const { attributes, children, element } = props

if (isTableFamilyNode(element)) {
const tableElement = renderElementTable()({ attributes, children, element })
if (tableElement) {
return tableElement
}
}

switch (element.type) {
case 'block-quote':
return <blockquote {...attributes}>{children}</blockquote>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ const BaseToolbarButton = ({ onClick, active, children }: ButtonProps) => {

<style jsx>{`
.toolbar-button {
height: 100%;
width: 24px;
height: 24px;
padding: 1px;
box-sizing: content-box;
border: none;
border-radius: 5px;
background-color: ${theme.colors.gray800};
Expand Down
46 changes: 21 additions & 25 deletions packages/web/components/JournalyEditor/Toolbar/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import React, { useEffect, useState } from 'react'
import classNames from 'classnames'
import { Popup } from 'reactjs-popup'
import {
ToolbarTable,
TableToolbarButton,
deleteTable,
deleteColumn,
addColumn,
insertTableColumn,
deleteRow,
addRow,
} from '@udecode/slate-plugins'
import { useSlate, useFocused } from 'slate-react'
insertTableRow,
} from '@udecode/plate'
import { useSlate } from 'slate-react'

import theme from '@/theme'

Expand All @@ -27,7 +27,7 @@ import FormatListBulletedIcon from '@/components/Icons/FormatListBulletedIcon'
import ToggleMarkButton from './ToggleMarkButton'
import ToolbarButton from './ToolbarButton'
import InsertImageButton from './InsertImageButton'
import { options, isTableActive } from '../helpers'
import { isTableActive } from '../helpers'
import SwitchToggle from '@/components/SwitchToggle'
import { useTranslation } from '@/config/i18n'
import useIntersectionObserver from '@/hooks/userIntersectionObserver'
Expand All @@ -48,12 +48,13 @@ const Toolbar = ({
const [viewportsDiff, setViewportsDiff] = useState(0)

const editor = useSlate()
const isEditorFocused = useFocused()
const isTableActivated = isEditorFocused && isTableActive(editor)
const isTableActivated = isTableActive(editor)
const tableIcon = (
<ToolbarButton type="table" format="insert-table">
<FormatTableIcon title="Insert table" titleId="toolbar-insert-table-icon" />
</ToolbarButton>
<div>
<ToolbarButton type="table" format="insert-table">
<FormatTableIcon title="Insert table" titleId="toolbar-insert-table-icon" />
</ToolbarButton>
</div>
)

const [toolbarObserverRef, toolbarShouldFloat] = useIntersectionObserver({
Expand Down Expand Up @@ -116,38 +117,33 @@ const Toolbar = ({

{isTableActivated ? (
<Popup
trigger={<span>{tableIcon}</span>}
trigger={tableIcon}
position="bottom center"
on={['hover', 'focus']}
on={['hover', 'focus', 'click']}
closeOnDocumentClick
className="editor-toolbar-popover"
>
<ToolbarTable
{...options}
<TableToolbarButton
className="editor-toolbar-popover-item"
transform={addRow}
transform={insertTableRow}
icon="Add row"
/>
<ToolbarTable
{...options}
<TableToolbarButton
className="editor-toolbar-popover-item"
transform={deleteRow}
icon="Delete row"
/>
<ToolbarTable
{...options}
<TableToolbarButton
className="editor-toolbar-popover-item"
transform={addColumn}
transform={insertTableColumn}
icon="Add column"
/>
<ToolbarTable
{...options}
<TableToolbarButton
className="editor-toolbar-popover-item"
transform={deleteColumn}
icon="Delete column"
/>
<ToolbarTable
{...options}
<TableToolbarButton
className="editor-toolbar-popover-item"
transform={deleteTable}
icon="Delete table"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback } from 'react'
import { useSlate, useFocused } from 'slate-react'
import { useSlate } from 'slate-react'

import { useTranslation } from '@/config/i18n'

Expand All @@ -15,8 +15,7 @@ type ButtonProps = {
const ToolbarButton = ({ type, format, children }: ButtonProps) => {
const { t } = useTranslation('post')
const editor = useSlate()
const isEditorFocused = useFocused()
const active = isEditorFocused && isTypeActive({ type, format, editor })
const active = isTypeActive({ type, format, editor })

const handleClick = useCallback((event: React.MouseEvent) => {
event.preventDefault()
Expand Down
13 changes: 8 additions & 5 deletions packages/web/components/JournalyEditor/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import {
} from 'slate'
import { toast } from 'react-toastify'
import { TFunction } from 'next-i18next'
import { DEFAULTS_TABLE, setDefaults, someNode, insertTable } from '@udecode/slate-plugins'
import {
PlateEditor,
someNode,
insertTable,
ELEMENT_TABLE
} from '@udecode/plate'
import { LinkElement } from '@/utils/slate'

export type ButtonType = 'block' | 'link' | 'table'
Expand Down Expand Up @@ -51,8 +56,6 @@ type ToggleByTypeArgs = {

type ToggleArgs = Omit<ToggleByTypeArgs, 'type'>

export const options = setDefaults(DEFAULTS_TABLE, {})

const LIST_TYPES = ['numbered-list', 'bulleted-list']

const validateProtocol = (href: string) => {
Expand Down Expand Up @@ -93,7 +96,7 @@ const isBlockActive = (editor: Editor, format: string) => {
const isLinkActive = (editor: Editor) => isBlockActive(editor, 'link')

export const isTableActive = (editor: Editor) => {
return someNode(editor, { match: { type: options.table.type } })
return someNode(editor as PlateEditor, { match: { type: ELEMENT_TABLE } })
}

export const tableHandler = ({ editor, format }: ToggleArgs) => {
Expand All @@ -103,7 +106,7 @@ export const tableHandler = ({ editor, format }: ToggleArgs) => {

const tableFormatKey = format as keyof typeof tableActions
if (tableActions[tableFormatKey]) {
tableActions[tableFormatKey](editor, options)
tableActions[tableFormatKey](editor as PlateEditor, {})
}
}

Expand Down
Loading