-
-
Notifications
You must be signed in to change notification settings - Fork 721
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: getNodeDeserializer supports dynamic style rules + example
- Loading branch information
Showing
17 changed files
with
551 additions
and
129 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@udecode/slate-plugins-common": patch | ||
--- | ||
|
||
getNodeDeserializer now supports dynamic style rules by providing an asterisk instead of an exact value | ||
documentation: adds a font color example that leverages the changed deserializer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
--- | ||
slug: /examples/font-color | ||
title: Font color | ||
--- | ||
|
||
:::note | ||
|
||
Most of the following variables are exported from the library or defined in the corresponding example. | ||
For quick lookup, jump to the [source code](https://github.com/udecode/slate-plugins/blob/main/docs/src/live/live.tsx). | ||
|
||
::: | ||
|
||
The following playground shows an example how to handle dynamic marks | ||
|
||
```ts live | ||
() => { | ||
let styledComponents = createSlatePluginsComponents({ | ||
...components, | ||
[MARK_COLOR]: withMarkedProps(StyledLeaf, { | ||
marks: [MARK_COLOR], | ||
}), | ||
}); | ||
styledComponents = withStyledPlaceHolders(styledComponents); | ||
|
||
const defaultOptions = createSlatePluginsOptions(); | ||
|
||
const CopyContent = () => ( | ||
<div style={{borderBottom: '1px solid #eee', margin: '0 -16px', padding: '0 16px 16px'}}> | ||
<span style={{color: '#f92672'}}>Copy Me in the editor</span> | ||
</div> | ||
); | ||
|
||
const SltEditor = () => { | ||
const { setSearch, plugin: searchHighlightPlugin } = useFindReplacePlugin(); | ||
|
||
const pluginsMemo = useMemo(() => { | ||
const plugins = [ | ||
createColorPlugin(), | ||
createReactPlugin(), | ||
createHistoryPlugin(), | ||
createParagraphPlugin(), | ||
createHeadingPlugin(), | ||
createBoldPlugin(), | ||
createCodePlugin(), | ||
createItalicPlugin(), | ||
createHighlightPlugin(), | ||
createUnderlinePlugin(), | ||
createStrikethroughPlugin(), | ||
createAutoformatPlugin(optionsAutoformat), | ||
createResetNodePlugin(optionsResetBlockTypePlugin), | ||
createSoftBreakPlugin(optionsSoftBreakPlugin), | ||
createExitBreakPlugin(optionsExitBreakPlugin), | ||
createNormalizeTypesPlugin({ | ||
rules: [{ path: [0], strictType: ELEMENT_H1 }], | ||
}), | ||
]; | ||
|
||
plugins.push(createDeserializeHTMLPlugin({ plugins })); | ||
|
||
return plugins; | ||
}, [options, searchHighlightPlugin]); | ||
|
||
const initialValue = [ | ||
...initialValueBasicMarks, | ||
{ | ||
type: ELEMENT_PARAGRAPH, | ||
children: [ | ||
{ | ||
text: 'This text is bold, italic and underlined and colored.', | ||
[MARK_BOLD]: true, | ||
[MARK_ITALIC]: true, | ||
[MARK_UNDERLINE]: true, | ||
[MARK_COLOR]: '#f92672' | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
return ( | ||
<SlatePlugins | ||
id="playground" | ||
plugins={pluginsMemo} | ||
components={styledComponents} | ||
options={defaultOptions} | ||
editableProps={editableProps} | ||
initialValue={initialValue} | ||
> | ||
<HeadingToolbar> | ||
<ToolbarColorPicker icon={<FormatColorText />} /> | ||
</HeadingToolbar> | ||
<CopyContent /> | ||
</SlatePlugins> | ||
); | ||
} | ||
|
||
return <SltEditor />; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
docs/src/live/examples/font-color/components/ColorPicker.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import * as React from 'react'; | ||
|
||
export const ColorPicker = ({ | ||
color, | ||
updateColor, | ||
}: { | ||
color: string | undefined; | ||
updateColor: (ev: any, colorObj: string) => void; | ||
}) => { | ||
return ( | ||
<div style={{ display: 'flex' }}> | ||
<input | ||
type="color" | ||
onChange={(ev) => updateColor(ev, ev.target.value)} | ||
value={color || '#000000'} | ||
/> | ||
</div> | ||
); | ||
}; |
73 changes: 73 additions & 0 deletions
73
docs/src/live/examples/font-color/components/ToolbarColorPicker.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import 'tippy.js/animations/scale.css'; | ||
import 'tippy.js/dist/tippy.css'; | ||
import React, { | ||
ReactNode, | ||
useCallback, | ||
useEffect, | ||
useRef, | ||
useState, | ||
} from 'react'; | ||
import { | ||
getSlatePluginType, | ||
ToolbarButton, | ||
useStoreEditorRef, | ||
useStoreEditorSelection, | ||
} from '@udecode/slate-plugins'; | ||
import { | ||
useEventEditorId, | ||
useStoreEditorState, | ||
} from '@udecode/slate-plugins-core'; | ||
import { BaseSelection, Transforms } from 'slate'; | ||
import { ReactEditor } from 'slate-react'; | ||
import { MARK_COLOR } from '../defaults'; | ||
import { getMark } from '../utils/getMark'; | ||
import { setMark } from '../utils/setMark'; | ||
import { ColorPicker } from './ColorPicker'; | ||
import { ToolbarDropdown } from './ToolbarDropdown'; | ||
|
||
export const ToolbarColorPicker = ({ icon }: { icon: ReactNode }) => { | ||
const editor = useStoreEditorState(useEventEditorId('focus')); | ||
const editorRef = useStoreEditorRef(useEventEditorId('focus')); | ||
const selection = useStoreEditorSelection(useEventEditorId('focus')); | ||
const type = getSlatePluginType(editor, MARK_COLOR); | ||
|
||
const color = editorRef && getMark(editorRef, type); | ||
|
||
const [selectedColor, setSelectedColor] = useState<string>(); | ||
|
||
const latestSelection = useRef<BaseSelection>(); | ||
|
||
const updateColor = useCallback((ev: any, colorParam: string) => { | ||
setSelectedColor(colorParam); | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (selection) { | ||
latestSelection.current = selection; | ||
setSelectedColor(color); | ||
} | ||
}, [color, selection]); | ||
|
||
return ( | ||
<ToolbarDropdown | ||
control={ | ||
<ToolbarButton | ||
active={!!editor?.selection && !!type && !!getMark(editor, type)} | ||
icon={icon} | ||
/> | ||
} | ||
onClose={(ev: MouseEvent) => { | ||
if (editorRef && editor && latestSelection.current) { | ||
ev.preventDefault(); | ||
Transforms.select(editorRef, latestSelection.current); | ||
ReactEditor.focus(editorRef); | ||
if (selectedColor) { | ||
setMark(editor, type, selectedColor); | ||
} | ||
} | ||
}} | ||
> | ||
<ColorPicker color={selectedColor || color} updateColor={updateColor} /> | ||
</ToolbarDropdown> | ||
); | ||
}; |
64 changes: 64 additions & 0 deletions
64
docs/src/live/examples/font-color/components/ToolbarDropdown.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React, { ReactNode, useEffect, useState } from 'react'; | ||
|
||
export const ToolbarDropdown = ({ | ||
control, | ||
children, | ||
onClose, | ||
}: { | ||
control: ReactNode; | ||
children: ReactNode; | ||
onClose?: (ev: MouseEvent) => void; | ||
}) => { | ||
const [ | ||
referenceElement, | ||
setReferenceElement, | ||
] = useState<HTMLDivElement | null>(null); | ||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>( | ||
null | ||
); | ||
|
||
const [open, setOpen] = useState(false); | ||
|
||
useEffect(() => { | ||
const listener = (ev: MouseEvent) => { | ||
if (open) { | ||
if (referenceElement && ev.composedPath().includes(referenceElement)) { | ||
return; | ||
} | ||
if (popperElement && ev.composedPath().includes(popperElement)) { | ||
return; | ||
} | ||
|
||
setOpen(false); | ||
onClose && typeof onClose === 'function' && onClose(ev); | ||
} | ||
}; | ||
document.body.addEventListener('mousedown', listener); | ||
return () => { | ||
document.body.removeEventListener('mousedown', listener); | ||
}; | ||
}, [onClose, open, popperElement, referenceElement, setOpen]); | ||
|
||
return ( | ||
<> | ||
<div ref={setReferenceElement} onMouseDown={() => setOpen(true)}> | ||
{control} | ||
</div> | ||
|
||
<div | ||
ref={setPopperElement} | ||
style={{ | ||
position: 'absolute', | ||
top: '40px', | ||
backgroundColor: 'white', | ||
border: '1px solid #ccc', | ||
boxShadow: '0 1px 3px 0 #ccc', | ||
zIndex: 1, | ||
display: open ? 'initial' : 'none', | ||
}} | ||
> | ||
{children} | ||
</div> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {getRenderLeaf} from '@udecode/slate-plugins'; | ||
import {SlatePlugin} from '@udecode/slate-plugins-core'; | ||
import {MARK_COLOR} from './defaults'; | ||
import {getColorDeserialize} from './getColorDeserialize'; | ||
|
||
export const createColorPlugin = (): SlatePlugin => ({ | ||
pluginKeys: MARK_COLOR, | ||
renderLeaf: getRenderLeaf(MARK_COLOR), | ||
deserialize: getColorDeserialize(), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export const MARK_COLOR = 'color'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import {Deserialize, getSlatePluginOptions,} from '@udecode/slate-plugins-core'; | ||
import {MARK_COLOR} from "./defaults"; | ||
import {getNodeDeserializer} from "@udecode/slate-plugins"; | ||
|
||
export const getColorDeserialize = (): Deserialize => (editor) => { | ||
const options = getSlatePluginOptions(editor, MARK_COLOR); | ||
|
||
return { | ||
leaf: getNodeDeserializer({ | ||
type: options.type, | ||
getNode: (element) => ({ [options.type]: element.style.color }), | ||
rules: [ | ||
{ | ||
style: { | ||
color: '*', | ||
}, | ||
}, | ||
], | ||
...options.deserialize, | ||
}), | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* @file Automatically generated by barrelsby. | ||
*/ | ||
|
||
export * from './createColorPlugin'; | ||
export * from './defaults'; | ||
export * from './getColorDeserialize'; | ||
export * from './utils/withMarkedProps'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { BaseEditor, Editor } from 'slate'; | ||
|
||
/** | ||
* Return the marks in the selection. | ||
* @param editor | ||
* @param type | ||
*/ | ||
export const getMark = (editor: BaseEditor, type: string): any => { | ||
if (!editor) { | ||
return; | ||
} | ||
|
||
const marks = Editor.marks(editor); | ||
return marks && marks[type]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { removeMark } from '@udecode/slate-plugins'; | ||
import { TEditor } from '@udecode/slate-plugins-core'; | ||
import castArray from 'lodash/castArray'; | ||
import { getMark } from './getMark'; | ||
|
||
/** | ||
* Add/remove marks in the selection. | ||
* @param editor | ||
* @param mark mark to toggle | ||
* @param value | ||
* @param clear marks to clear when adding mark | ||
*/ | ||
export const setMark = ( | ||
editor: TEditor, | ||
mark: string, | ||
value: any = true, | ||
clear: string | string[] = [] | ||
) => { | ||
if (!editor?.selection) { | ||
return; | ||
} | ||
|
||
const activeMark = getMark(editor, mark); | ||
|
||
if (activeMark) { | ||
removeMark(editor, { key: mark }); | ||
} | ||
|
||
const clears: string[] = castArray(clear); | ||
clears.forEach((item) => { | ||
removeMark(editor, { key: item }); | ||
}); | ||
|
||
editor.addMark(mark, value); | ||
}; |
Oops, something went wrong.