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,
|
||||
SELECTION_CHANGE_COMMAND,
|
||||
FORMAT_TEXT_COMMAND,
|
||||
FORMAT_ELEMENT_COMMAND,
|
||||
COMMAND_PRIORITY_CRITICAL,
|
||||
$getSelection,
|
||||
$isRangeSelection,
|
||||
$isRootOrShadowRoot,
|
||||
$isElementNode,
|
||||
} from 'lexical';
|
||||
import type { TextFormatType } from 'lexical';
|
||||
import type { ElementFormatType, TextFormatType } from 'lexical';
|
||||
import { $getSelectionStyleValueForProperty, $patchStyleText } from '@lexical/selection';
|
||||
import { $findMatchingParent } from '@lexical/utils';
|
||||
|
||||
import DropdownColorPicker from '../ui/DropdownColorPicker';
|
||||
import '../styles/toolbar.css';
|
||||
@@ -30,6 +34,7 @@ export default function ToolbarPlugin() {
|
||||
const [fontColor, setFontColor] = useState('#000');
|
||||
const [bgColor, setBgColor] = useState('#fff');
|
||||
const [fontSize, setFontSize] = useState('15px');
|
||||
const [elementFormat, setElementFormat] = useState<ElementFormatType>('left');
|
||||
|
||||
const updateToolbar = useCallback(() => {
|
||||
const selection = $getSelection();
|
||||
@@ -51,6 +56,21 @@ export default function ToolbarPlugin() {
|
||||
setFontSize(
|
||||
$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]);
|
||||
|
||||
@@ -225,6 +245,40 @@ export default function ToolbarPlugin() {
|
||||
onChange={onBgColorSelect}
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -334,3 +334,20 @@
|
||||
left: -6px;
|
||||
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;
|
||||
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',
|
||||
strikethrough: 'editor-text-strikethrough',
|
||||
code: 'editor-text-code',
|
||||
left: 'editor-text-left',
|
||||
center: 'editor-text-center',
|
||||
right: 'editor-text-right',
|
||||
justify: 'editor-text-justify',
|
||||
},
|
||||
code: 'editor-code',
|
||||
codeHighlight: {},
|
||||
|
||||
Reference in New Issue
Block a user