feat: add text alignment options to toolbar with corresponding styles and commands
All checks were successful
CI - Build and Push / Build and Push Docker Image (push) Successful in 17s
All checks were successful
CI - Build and Push / Build and Push Docker Image (push) Successful in 17s
This commit is contained in:
@@ -7,12 +7,16 @@ import {
|
|||||||
UNDO_COMMAND,
|
UNDO_COMMAND,
|
||||||
SELECTION_CHANGE_COMMAND,
|
SELECTION_CHANGE_COMMAND,
|
||||||
FORMAT_TEXT_COMMAND,
|
FORMAT_TEXT_COMMAND,
|
||||||
|
FORMAT_ELEMENT_COMMAND,
|
||||||
COMMAND_PRIORITY_CRITICAL,
|
COMMAND_PRIORITY_CRITICAL,
|
||||||
$getSelection,
|
$getSelection,
|
||||||
$isRangeSelection,
|
$isRangeSelection,
|
||||||
|
$isRootOrShadowRoot,
|
||||||
|
$isElementNode,
|
||||||
} from 'lexical';
|
} from 'lexical';
|
||||||
import type { TextFormatType } from 'lexical';
|
import type { ElementFormatType, TextFormatType } from 'lexical';
|
||||||
import { $getSelectionStyleValueForProperty, $patchStyleText } from '@lexical/selection';
|
import { $getSelectionStyleValueForProperty, $patchStyleText } from '@lexical/selection';
|
||||||
|
import { $findMatchingParent } from '@lexical/utils';
|
||||||
|
|
||||||
import DropdownColorPicker from '../ui/DropdownColorPicker';
|
import DropdownColorPicker from '../ui/DropdownColorPicker';
|
||||||
import '../styles/toolbar.css';
|
import '../styles/toolbar.css';
|
||||||
@@ -30,6 +34,7 @@ export default function ToolbarPlugin() {
|
|||||||
const [fontColor, setFontColor] = useState('#000');
|
const [fontColor, setFontColor] = useState('#000');
|
||||||
const [bgColor, setBgColor] = useState('#fff');
|
const [bgColor, setBgColor] = useState('#fff');
|
||||||
const [fontSize, setFontSize] = useState('15px');
|
const [fontSize, setFontSize] = useState('15px');
|
||||||
|
const [elementFormat, setElementFormat] = useState<ElementFormatType>('left');
|
||||||
|
|
||||||
const updateToolbar = useCallback(() => {
|
const updateToolbar = useCallback(() => {
|
||||||
const selection = $getSelection();
|
const selection = $getSelection();
|
||||||
@@ -51,6 +56,21 @@ export default function ToolbarPlugin() {
|
|||||||
setFontSize(
|
setFontSize(
|
||||||
$getSelectionStyleValueForProperty(selection, 'font-size', '15px')
|
$getSelectionStyleValueForProperty(selection, 'font-size', '15px')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Update element format (alignment)
|
||||||
|
const node = selection.anchor.getNode();
|
||||||
|
const element =
|
||||||
|
node.getKey() === 'root'
|
||||||
|
? node
|
||||||
|
: $findMatchingParent(node, (e) => {
|
||||||
|
const parent = e.getParent();
|
||||||
|
return parent !== null && $isRootOrShadowRoot(parent);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (element !== null && $isElementNode(element)) {
|
||||||
|
const formatType = element.getFormatType();
|
||||||
|
setElementFormat(formatType || 'left');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [editor]);
|
}, [editor]);
|
||||||
|
|
||||||
@@ -225,6 +245,40 @@ export default function ToolbarPlugin() {
|
|||||||
onChange={onBgColorSelect}
|
onChange={onBgColorSelect}
|
||||||
title="bg color"
|
title="bg color"
|
||||||
/>
|
/>
|
||||||
|
<div className="divider" />
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'left');
|
||||||
|
}}
|
||||||
|
className={'toolbar-item spaced ' + (elementFormat === 'left' ? 'active' : '')}
|
||||||
|
aria-label="Left Align">
|
||||||
|
<i className="format left-align" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'center');
|
||||||
|
}}
|
||||||
|
className={'toolbar-item spaced ' + (elementFormat === 'center' ? 'active' : '')}
|
||||||
|
aria-label="Center Align">
|
||||||
|
<i className="format center-align" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'right');
|
||||||
|
}}
|
||||||
|
className={'toolbar-item spaced ' + (elementFormat === 'right' ? 'active' : '')}
|
||||||
|
aria-label="Right Align">
|
||||||
|
<i className="format right-align" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'justify');
|
||||||
|
}}
|
||||||
|
className={'toolbar-item spaced ' + (elementFormat === 'justify' ? 'active' : '')}
|
||||||
|
aria-label="Justify Align">
|
||||||
|
<i className="format justify-align" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,3 +334,20 @@
|
|||||||
left: -6px;
|
left: -6px;
|
||||||
cursor: nw-resize;
|
cursor: nw-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Text Alignment */
|
||||||
|
.editor-text-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-text-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-text-justify {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|||||||
@@ -128,3 +128,19 @@ i.icon.bg-color {
|
|||||||
width: 18px;
|
width: 18px;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i.format.left-align {
|
||||||
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="15" y2="12"/><line x1="3" y1="18" x2="18" y2="18"/></svg>');
|
||||||
|
}
|
||||||
|
|
||||||
|
i.format.center-align {
|
||||||
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="6" y1="12" x2="18" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>');
|
||||||
|
}
|
||||||
|
|
||||||
|
i.format.right-align {
|
||||||
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="9" y1="12" x2="21" y2="12"/><line x1="6" y1="18" x2="21" y2="18"/></svg>');
|
||||||
|
}
|
||||||
|
|
||||||
|
i.format.justify-align {
|
||||||
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>');
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ const theme: EditorThemeClasses = {
|
|||||||
underline: 'editor-text-underline',
|
underline: 'editor-text-underline',
|
||||||
strikethrough: 'editor-text-strikethrough',
|
strikethrough: 'editor-text-strikethrough',
|
||||||
code: 'editor-text-code',
|
code: 'editor-text-code',
|
||||||
|
left: 'editor-text-left',
|
||||||
|
center: 'editor-text-center',
|
||||||
|
right: 'editor-text-right',
|
||||||
|
justify: 'editor-text-justify',
|
||||||
},
|
},
|
||||||
code: 'editor-code',
|
code: 'editor-code',
|
||||||
codeHighlight: {},
|
codeHighlight: {},
|
||||||
|
|||||||
Reference in New Issue
Block a user