fix: heading and boldness inconsistencies
This commit is contained in:
1 parent
ae81b93662
commit
e5b7528c24
3 files changed
+85
-7
No files matched your search
@@ -4,12 +4,16 @@
|
||||
let { editor, tick }: { editor: Editor | null; tick: number } = $props();
|
||||
|
||||
// $derived re-evaluates whenever `tick` changes (i.e. on every TipTap transaction)
|
||||
let isBold = $derived(tick >= 0 && !!editor?.isActive('bold'));
|
||||
let isItalic = $derived(tick >= 0 && !!editor?.isActive('italic'));
|
||||
let isUnderline = $derived(tick >= 0 && !!editor?.isActive('underline'));
|
||||
let isH1 = $derived(tick >= 0 && !!editor?.isActive('heading', { level: 1 }));
|
||||
let isH2 = $derived(tick >= 0 && !!editor?.isActive('heading', { level: 2 }));
|
||||
let isH3 = $derived(tick >= 0 && !!editor?.isActive('heading', { level: 3 }));
|
||||
let isHeading = $derived(isH1 || isH2 || isH3);
|
||||
// fontWeight:'normal' is set explicitly to override heading boldness
|
||||
let hasNormalWeight = $derived(tick >= 0 && !!editor?.isActive('textStyle', { fontWeight: 'normal' }));
|
||||
// Bold = explicit bold mark, OR inside a heading that hasn't been un-bolded
|
||||
let isBold = $derived(tick >= 0 && (!!editor?.isActive('bold') || (isHeading && !hasNormalWeight)));
|
||||
let isItalic = $derived(tick >= 0 && !!editor?.isActive('italic'));
|
||||
let isUnderline = $derived(tick >= 0 && !!editor?.isActive('underline'));
|
||||
let isBulletList = $derived(tick >= 0 && !!editor?.isActive('bulletList'));
|
||||
let isOrderedList= $derived(tick >= 0 && !!editor?.isActive('orderedList'));
|
||||
let canUndo = $derived(tick >= 0 && !!editor?.can().undo());
|
||||
@@ -21,7 +25,19 @@
|
||||
<div class="toolbar-group">
|
||||
<button
|
||||
class:active={isBold}
|
||||
onclick={() => editor?.chain().focus().toggleBold().run()}
|
||||
onclick={() => {
|
||||
if (isHeading) {
|
||||
if (hasNormalWeight) {
|
||||
// Restore heading's natural bold
|
||||
editor?.chain().focus().unsetFontWeight().run();
|
||||
} else {
|
||||
// Override heading bold with explicit font-weight: normal
|
||||
editor?.chain().focus().setFontWeight('normal').run();
|
||||
}
|
||||
} else {
|
||||
editor?.chain().focus().toggleBold().run();
|
||||
}
|
||||
}}
|
||||
title="Bold (Ctrl+B)"
|
||||
>
|
||||
<strong>B</strong>
|
||||
@@ -47,21 +63,21 @@
|
||||
<div class="toolbar-group">
|
||||
<button
|
||||
class:active={isH1}
|
||||
onclick={() => editor?.chain().focus().toggleHeading({ level: 1 }).unsetFontSize().removeEmptyTextStyle().run()}
|
||||
onclick={() => editor?.chain().focus().toggleHeading({ level: 1 }).unsetFontSize().unsetFontWeight().removeEmptyTextStyle().run()}
|
||||
title="Heading 1"
|
||||
>
|
||||
H1
|
||||
</button>
|
||||
<button
|
||||
class:active={isH2}
|
||||
onclick={() => editor?.chain().focus().toggleHeading({ level: 2 }).unsetFontSize().removeEmptyTextStyle().run()}
|
||||
onclick={() => editor?.chain().focus().toggleHeading({ level: 2 }).unsetFontSize().unsetFontWeight().removeEmptyTextStyle().run()}
|
||||
title="Heading 2"
|
||||
>
|
||||
H2
|
||||
</button>
|
||||
<button
|
||||
class:active={isH3}
|
||||
onclick={() => editor?.chain().focus().toggleHeading({ level: 3 }).unsetFontSize().removeEmptyTextStyle().run()}
|
||||
onclick={() => editor?.chain().focus().toggleHeading({ level: 3 }).unsetFontSize().unsetFontWeight().removeEmptyTextStyle().run()}
|
||||
title="Heading 3"
|
||||
>
|
||||
H3
|
||||
|
||||
@@ -5,6 +5,7 @@ import Bold from '@tiptap/extension-bold';
|
||||
import Italic from '@tiptap/extension-italic';
|
||||
import Underline from '@tiptap/extension-underline';
|
||||
import { TextStyle, FontFamily, FontSize } from '@tiptap/extension-text-style';
|
||||
import { FontWeight } from './fontWeight';
|
||||
import Heading from '@tiptap/extension-heading';
|
||||
import BulletList from '@tiptap/extension-bullet-list';
|
||||
import OrderedList from '@tiptap/extension-ordered-list';
|
||||
@@ -24,6 +25,7 @@ export const extensions = [
|
||||
TextStyle,
|
||||
FontFamily,
|
||||
FontSize,
|
||||
FontWeight,
|
||||
LineHeight,
|
||||
Heading.configure({ levels: [1, 2, 3] }),
|
||||
BulletList,
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Extension } from '@tiptap/core';
|
||||
import '@tiptap/extension-text-style';
|
||||
|
||||
declare module '@tiptap/core' {
|
||||
interface Commands<ReturnType> {
|
||||
fontWeight: {
|
||||
setFontWeight: (weight: string) => ReturnType;
|
||||
unsetFontWeight: () => ReturnType;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds `fontWeight` as an attribute on the TextStyle mark so that
|
||||
* font-weight can be set as an inline style (e.g. 'normal' to override
|
||||
* the bold appearance of a heading without changing the node type).
|
||||
*/
|
||||
export const FontWeight = Extension.create({
|
||||
name: 'fontWeight',
|
||||
|
||||
addOptions() {
|
||||
return { types: ['textStyle'] };
|
||||
},
|
||||
|
||||
addGlobalAttributes() {
|
||||
return [
|
||||
{
|
||||
types: this.options.types,
|
||||
attributes: {
|
||||
fontWeight: {
|
||||
default: null,
|
||||
parseHTML: element =>
|
||||
element.style.fontWeight?.replace(/['"]+/g, '') || null,
|
||||
renderHTML: attributes => {
|
||||
if (!attributes.fontWeight) return {};
|
||||
return { style: `font-weight: ${attributes.fontWeight}` };
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
return {
|
||||
setFontWeight:
|
||||
(fontWeight: string) =>
|
||||
({ chain }) =>
|
||||
chain().setMark('textStyle', { fontWeight }).run(),
|
||||
|
||||
unsetFontWeight:
|
||||
() =>
|
||||
({ chain }) =>
|
||||
chain()
|
||||
.setMark('textStyle', { fontWeight: null })
|
||||
.removeEmptyTextStyle()
|
||||
.run(),
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in new issue
Block a user