Skip to content

Support h4, h5, and h6 #1634

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
93e4c12
Adding H4/H5 blocks
DrewJohnsonGT Apr 22, 2025
4c893f5
Adding translations for h4/h5
DrewJohnsonGT Apr 22, 2025
285c600
Styles
DrewJohnsonGT Apr 22, 2025
75c144e
Font size and test
DrewJohnsonGT Apr 22, 2025
a969173
Update snapshot tests
DrewJohnsonGT Apr 22, 2025
86da278
locales and other h6 support updates
DrewJohnsonGT Apr 23, 2025
3eb5a97
Update snapshot tests with h6
DrewJohnsonGT Apr 23, 2025
9f47f75
Add the h6 icon for slash menu item
DrewJohnsonGT Apr 23, 2025
0cf25c0
Test H6 notion snapshot
DrewJohnsonGT Apr 23, 2025
37f7501
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 2, 2025
90cfa70
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 7, 2025
72f9a1d
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 13, 2025
ed36dc6
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 15, 2025
e4da76f
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 16, 2025
738984b
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 19, 2025
d06e86e
zh locale and pdf export
DrewJohnsonGT May 20, 2025
16d3b9d
Merge branch 'TypeCellOS:main' into support-h4-h6
DrewJohnsonGT May 20, 2025
1e0bd42
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 20, 2025
c424493
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 20, 2025
c0826e2
Update tests for new heading levels
DrewJohnsonGT May 21, 2025
fbb0bf9
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 22, 2025
5cabb32
Merge branch 'main' into support-h4-h6
DrewJohnsonGT May 23, 2025
5034f4d
Merge branch 'main' into support-h4-h6
DrewJohnsonGT Jun 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 30 additions & 73 deletions packages/core/src/blocks/HeadingBlockContent/HeadingBlockContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import {
import { createDefaultBlockDOMOutputSpec } from "../defaultBlockHelpers.js";
import { defaultProps } from "../defaultProps.js";

const HEADING_LEVELS = [1, 2, 3, 4, 5, 6] as const;

export const headingPropSchema = {
...defaultProps,
level: { default: 1, values: [1, 2, 3] as const },
level: { default: 1, values: HEADING_LEVELS },
} satisfies PropSchema;

const HeadingBlockContent = createStronglyTypedTiptapNode({
Expand All @@ -26,7 +28,7 @@ const HeadingBlockContent = createStronglyTypedTiptapNode({

addInputRules() {
return [
...[1, 2, 3].map((level) => {
...HEADING_LEVELS.map((level) => {
// Creates a heading of appropriate level when starting with "#", "##", or "###".
return new InputRule({
find: new RegExp(`^(#{${level}})\\s$`),
Expand Down Expand Up @@ -58,63 +60,29 @@ const HeadingBlockContent = createStronglyTypedTiptapNode({
},

addKeyboardShortcuts() {
return {
"Mod-Alt-1": () => {
const blockInfo = getBlockInfoFromSelection(this.editor.state);
if (
!blockInfo.isBlockContainer ||
blockInfo.blockContent.node.type.spec.content !== "inline*"
) {
return true;
}

// call updateBlockCommand
return this.editor.commands.command(
updateBlockCommand(blockInfo.bnBlock.beforePos, {
type: "heading",
props: {
level: 1 as any,
},
}),
);
},
"Mod-Alt-2": () => {
const blockInfo = getBlockInfoFromSelection(this.editor.state);
if (
!blockInfo.isBlockContainer ||
blockInfo.blockContent.node.type.spec.content !== "inline*"
) {
return true;
}

return this.editor.commands.command(
updateBlockCommand(blockInfo.bnBlock.beforePos, {
type: "heading",
props: {
level: 2 as any,
},
}),
);
},
"Mod-Alt-3": () => {
const blockInfo = getBlockInfoFromSelection(this.editor.state);
if (
!blockInfo.isBlockContainer ||
blockInfo.blockContent.node.type.spec.content !== "inline*"
) {
return true;
}
return Object.fromEntries(
HEADING_LEVELS.map((level) => [
`Mod-Alt-${level}`,
() => {
const blockInfo = getBlockInfoFromSelection(this.editor.state);
if (
!blockInfo.isBlockContainer ||
blockInfo.blockContent.node.type.spec.content !== "inline*"
) {
return true;
}

return this.editor.commands.command(
updateBlockCommand(blockInfo.bnBlock.beforePos, {
type: "heading",
props: {
level: 3 as any,
},
}),
);
},
};
return this.editor.commands.command(
updateBlockCommand(blockInfo.bnBlock.beforePos, {
type: "heading",
props: {
level: level as any,
},
})
);
},
])
);
},
parseHTML() {
return [
Expand All @@ -123,22 +91,11 @@ const HeadingBlockContent = createStronglyTypedTiptapNode({
tag: "div[data-content-type=" + this.name + "]",
contentElement: ".bn-inline-content",
},
// Parse from external HTML.
{
tag: "h1",
attrs: { level: 1 },
...HEADING_LEVELS.map((level) => ({
tag: `h${level}`,
attrs: { level },
node: "heading",
},
{
tag: "h2",
attrs: { level: 2 },
node: "heading",
},
{
tag: "h3",
attrs: { level: 3 },
node: "heading",
},
})),
];
},

Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/editor/Block.css
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ NESTED BLOCKS
[data-content-type="heading"][data-level="3"] {
--level: 1.3em;
}
[data-content-type="heading"][data-level="4"] {
--level: 1em;
}
[data-content-type="heading"][data-level="5"] {
--level: 0.9em;
}
[data-content-type="heading"][data-level="6"] {
--level: 0.8em;
}

[data-prev-level="1"] {
--prev-level: 3em;
Expand All @@ -144,6 +153,15 @@ NESTED BLOCKS
[data-prev-level="3"] {
--prev-level: 1.3em;
}
[data-prev-level="4"] {
--prev-level: 1em;
}
[data-prev-level="5"] {
--prev-level: 0.9em;
}
[data-prev-level="6"] {
--prev-level: 0.8em;
}

.bn-block-outer[data-prev-type="heading"] > .bn-block > .bn-block-content {
font-size: var(--prev-level);
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/editor/editor.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ Tippy popups that are appended to document.body directly
.bn-default-styles h1,
.bn-default-styles h2,
.bn-default-styles h3,
.bn-default-styles h4,
.bn-default-styles h5,
.bn-default-styles h6,
.bn-default-styles li {
margin: 0;
padding: 0;
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/i18n/locales/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ export const ar: Dictionary = {
aliases: ["ع3", "عنوان3", "عنوان فرعي"],
group: "العناوين",
},
heading_4: {
title: "عنوان 4",
subtext: "عنوان فرعي ثانوي صغير",
aliases: ["ع4", "عنوان4", "عنوان فرعي صغير"],
group: "العناوين",
},
heading_5: {
title: "عنوان 5",
subtext: "عنوان فرعي صغير",
aliases: ["ع5", "عنوان5", "عنوان فرعي صغير"],
group: "العناوين",
},
heading_6: {
title: "عنوان 6",
subtext: "أدنى مستوى للعناوين",
aliases: ["ع6", "عنوان6", "العنوان الفرعي الأدنى"],
group: "العناوين",
},
quote: {
title: "اقتباس",
subtext: "اقتباس أو مقتطف",
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/i18n/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ export const de: Dictionary = {
aliases: ["h3", "überschrift3", "unterüberschrift"],
group: "Überschriften",
},
heading_4: {
title: "Überschrift 4",
subtext: "Überschrift für kleinere Unterabschnitte",
aliases: ["h4", "überschrift4", "unterüberschrift4"],
group: "Überschriften",
},
heading_5: {
title: "Überschrift 5",
subtext: "Überschrift für tiefere Unterabschnitte",
aliases: ["h5", "überschrift5", "unterüberschrift5"],
group: "Überschriften",
},
heading_6: {
title: "Überschrift 6",
subtext: "Überschrift auf der untersten Ebene",
aliases: ["h6", "überschrift6", "unterüberschrift6"],
group: "Überschriften",
},
quote: {
title: "Zitat",
subtext: "Zitat oder Auszug",
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ export const en = {
aliases: ["h3", "heading3", "subheading"],
group: "Headings",
},
heading_4: {
title: "Heading 4",
subtext: "Minor subsection heading",
aliases: ["h4", "heading4", "subheading4"],
group: "Headings",
},
heading_5: {
title: "Heading 5",
subtext: "Small subsection heading",
aliases: ["h5", "heading5", "subheading5"],
group: "Headings",
},
heading_6: {
title: "Heading 6",
subtext: "Lowest-level heading",
aliases: ["h6", "heading6", "subheading6"],
group: "Headings",
},
quote: {
title: "Quote",
subtext: "Quote or excerpt",
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/i18n/locales/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ export const es: Dictionary = {
aliases: ["h3", "encabezado3", "subencabezado"],
group: "Encabezados",
},
heading_4: {
title: "Encabezado 4",
subtext: "Encabezado de subsección menor",
aliases: ["h4", "encabezado4", "subencabezado4"],
group: "Encabezados",
},
heading_5: {
title: "Encabezado 5",
subtext: "Encabezado de subsección pequeña",
aliases: ["h5", "encabezado5", "subencabezado5"],
group: "Encabezados",
},
heading_6: {
title: "Encabezado 6",
subtext: "Encabezado de nivel más bajo",
aliases: ["h6", "encabezado6", "subencabezado6"],
group: "Encabezados",
},
quote: {
title: "Cita",
subtext: "Cita o extracto",
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/i18n/locales/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ export const fr: Dictionary = {
aliases: ["h3", "titre3", "sous-titre"],
group: "Titres",
},
heading_4: {
title: "Titre 4",
subtext: "Titre de sous‑section mineure",
aliases: ["h4", "titre4", "sous‑titre4"],
group: "Titres",
},
heading_5: {
title: "Titre 5",
subtext: "Titre de sous-section mineure",
aliases: ["h5", "titre5", "sous-titre5"],
group: "Titres",
},
heading_6: {
title: "Titre 6",
subtext: "Titre de niveau le plus bas",
aliases: ["h6", "titre6", "sous-titre6"],
group: "Titres",
},
quote: {
title: "Citation",
subtext: "Citation ou extrait",
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/i18n/locales/hr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ export const hr: Dictionary = {
aliases: ["h3", "naslov3", "podnaslov"],
group: "Naslovi",
},
heading_4: {
title: "Naslov 4",
subtext: "Manji naslov podpoglavlja",
aliases: ["h4", "naslov4", "podnaslov4"],
group: "Naslovi",
},
heading_5: {
title: "Naslov 5",
subtext: "Mali naslov podpoglavlja",
aliases: ["h5", "naslov5", "podnaslov5"],
group: "Naslovi",
},
heading_6: {
title: "Naslov 6",
subtext: "Naslov najniže razine",
aliases: ["h6", "naslov6", "podnaslov6"],
group: "Naslovi",
},
quote: {
title: "Citat",
subtext: "Citat ili izvadak",
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/i18n/locales/is.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ export const is: Dictionary = {
aliases: ["h3", "fyrirsogn3", "undirfyrirsogn"],
group: "Fyrirsagnir",
},
heading_4: {
title: "Fyrirsögn 4",
subtext: "Titill fyrir minni undirhluta",
aliases: ["h4", "fyrirsogn4", "undirfyrirsogn4"],
group: "Fyrirsagnir",
},
heading_5: {
title: "Fyrirsögn 5",
subtext: "Titill fyrir litla undirkafla",
aliases: ["h5", "fyrirsogn5", "undirfyrirsogn5"],
group: "Fyrirsagnir",
},
heading_6: {
title: "Fyrirsögn 6",
subtext: "Titill á lægsta stigi",
aliases: ["h6", "fyrirsogn6", "undirfyrirsogn6"],
group: "Fyrirsagnir",
},
quote: {
title: "Tilvitnun",
subtext: "Tilvitnun eða útdráttur",
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/i18n/locales/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ export const it: Dictionary = {
aliases: ["h3", "intestazione3", "sottotitolo"],
group: "Intestazioni",
},
heading_4: {
title: "Intestazione 4",
subtext: "Intestazione di sottosezione minore",
aliases: ["h4", "intestazione4", "sottotitolo4"],
group: "Intestazioni",
},
heading_5: {
title: "Intestazione 5",
subtext: "Intestazione di sottosezione minore",
aliases: ["h5", "intestazione5", "sottotitolo5"],
group: "Intestazioni",
},
heading_6: {
title: "Intestazione 6",
subtext: "Intestazione di livello più basso",
aliases: ["h6", "intestazione6", "sottotitolo6"],
group: "Intestazioni",
},
quote: {
title: "Citazione",
subtext: "Citazione o estratto",
Expand Down
Loading
Loading