-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
150 additions
and
0 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
83 changes: 83 additions & 0 deletions
83
...-lexical/src/lib/components/toolbar/MoreStylesDropDown/ClearFormattingDropDownItem.svelte
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,83 @@ | ||
<script lang="ts"> | ||
import DropDownItem from '$lib/components/generic/dropdown/DropDownItem.svelte'; | ||
import {getActiveEditor} from '$lib/core/composerContext.js'; | ||
import {$isDecoratorBlockNode as isDecoratorBlockNode} from '$lib/core/plugins/DecoratorBlockNode.js'; | ||
import { | ||
$isQuoteNode as isQuoteNode, | ||
$isHeadingNode as isHeadingNode, | ||
} from '@lexical/rich-text'; | ||
import {$isTableSelection as isTableSelection} from '@lexical/table'; | ||
import {$getNearestBlockElementAncestorOrThrow as getNearestBlockElementAncestorOrThrow} from '@lexical/utils'; | ||
import { | ||
$isTextNode as isTextNode, | ||
$getSelection as getSelection, | ||
$isRangeSelection as isRangeSelection, | ||
$createParagraphNode as createParagraphNode, | ||
} from 'lexical'; | ||
const activeEditor = getActiveEditor(); | ||
function clearFormatting() { | ||
$activeEditor.update(() => { | ||
const selection = getSelection(); | ||
if (isRangeSelection(selection) || isTableSelection(selection)) { | ||
const anchor = selection.anchor; | ||
const focus = selection.focus; | ||
const nodes = selection.getNodes(); | ||
if (anchor.key === focus.key && anchor.offset === focus.offset) { | ||
return; | ||
} | ||
nodes.forEach((node, idx) => { | ||
// We split the first and last node by the selection | ||
// So that we don't format unselected text inside those nodes | ||
if (isTextNode(node)) { | ||
// Use a separate variable to ensure TS does not lose the refinement | ||
let textNode = node; | ||
if (idx === 0 && anchor.offset !== 0) { | ||
textNode = textNode.splitText(anchor.offset)[1] || textNode; | ||
} | ||
if (idx === nodes.length - 1) { | ||
textNode = textNode.splitText(focus.offset)[0] || textNode; | ||
} | ||
/** | ||
* If the selected text has one format applied | ||
* selecting a portion of the text, could | ||
* clear the format to the wrong portion of the text. | ||
* | ||
* The cleared text is based on the length of the selected text. | ||
*/ | ||
// We need this in case the selected text only has one format | ||
const extractedTextNode = selection.extract()[0]; | ||
if (nodes.length === 1 && isTextNode(extractedTextNode)) { | ||
textNode = extractedTextNode; | ||
} | ||
if (textNode.__style !== '') { | ||
textNode.setStyle(''); | ||
} | ||
if (textNode.__format !== 0) { | ||
textNode.setFormat(0); | ||
getNearestBlockElementAncestorOrThrow(textNode).setFormat(''); | ||
} | ||
node = textNode; | ||
} else if (isHeadingNode(node) || isQuoteNode(node)) { | ||
node.replace(createParagraphNode(), true); | ||
} else if (isDecoratorBlockNode(node)) { | ||
node.setFormat(''); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
</script> | ||
|
||
<DropDownItem | ||
on:click={clearFormatting} | ||
class="item" | ||
title="Clear text formatting" | ||
ariaLabel="Clear all text formatting"> | ||
<i class="icon clear" /> | ||
<span class="text">Clear Formatting</span> | ||
</DropDownItem> |
64 changes: 64 additions & 0 deletions
64
packages/svelte-lexical/src/lib/core/plugins/DecoratorBlockNode.ts
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 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
*/ | ||
|
||
import type { | ||
ElementFormatType, | ||
LexicalNode, | ||
NodeKey, | ||
SerializedLexicalNode, | ||
Spread, | ||
} from 'lexical'; | ||
|
||
import {DecoratorNode} from 'lexical'; | ||
|
||
export type SerializedDecoratorBlockNode = Spread< | ||
{ | ||
format: ElementFormatType; | ||
}, | ||
SerializedLexicalNode | ||
>; | ||
|
||
export class DecoratorBlockNode extends DecoratorNode<unknown> { | ||
__format: ElementFormatType; | ||
|
||
constructor(format?: ElementFormatType, key?: NodeKey) { | ||
super(key); | ||
this.__format = format || ''; | ||
} | ||
|
||
exportJSON(): SerializedDecoratorBlockNode { | ||
return { | ||
format: this.__format || '', | ||
type: 'decorator-block', | ||
version: 1, | ||
}; | ||
} | ||
|
||
createDOM(): HTMLElement { | ||
return document.createElement('div'); | ||
} | ||
|
||
updateDOM(): false { | ||
return false; | ||
} | ||
|
||
setFormat(format: ElementFormatType): void { | ||
const self = this.getWritable(); | ||
self.__format = format; | ||
} | ||
|
||
isInline(): false { | ||
return false; | ||
} | ||
} | ||
|
||
export function $isDecoratorBlockNode( | ||
node: LexicalNode | null | undefined, | ||
): node is DecoratorBlockNode { | ||
return node instanceof DecoratorBlockNode; | ||
} |
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