diff --git a/package.json b/package.json
index f5db143c7c15..490c2091e271 100644
--- a/package.json
+++ b/package.json
@@ -96,6 +96,7 @@
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"front-matter": "^4.0.2",
+ "github-slugger": "^1.4.0",
"html-webpack-plugin": "^5.5.0",
"http-server": "^14.1.0",
"husky": "^7.0.4",
@@ -105,6 +106,7 @@
"lodash": "^4.17.21",
"markdownlint": "^0.25.1",
"markdownlint-cli": "^0.31.0",
+ "mdast-util-to-string": "^3.1.0",
"mini-css-extract-plugin": "^2.5.3",
"mkdirp": "^1.0.4",
"modularscale-sass": "^3.0.3",
@@ -123,7 +125,6 @@
"remark-gfm": "^1.0.0",
"remark-html": "^15.0.1",
"remark-refractor": "montogeek/remark-refractor",
- "remark-slug": "^7.0.1",
"rimraf": "^3.0.2",
"sass": "^1.49.7",
"sass-loader": "^12.4.0",
diff --git a/src/components/Markdown/Markdown.scss b/src/components/Markdown/Markdown.scss
index f43030c17f0f..daabd9f61816 100644
--- a/src/components/Markdown/Markdown.scss
+++ b/src/components/Markdown/Markdown.scss
@@ -1,4 +1,4 @@
-@use "sass:color";
+@use 'sass:color';
@import 'vars';
@import 'functions';
@import 'prism-theme';
@@ -41,15 +41,16 @@ $topHeightMobileWithBanner: $bannerHeight + $topHeightMobile;
h4,
h5,
h6 {
- &:before {
- content: '';
+ > span[id] {
+ position: absolute;
+ width: 0;
display: block;
visibility: hidden;
pointer-events: none;
- height: $topHeightMobile;
+ padding-top: $topHeightMobile;
margin-top: -#{$topHeightMobile};
@include break {
- height: $topHeightDesktop;
+ padding-top: $topHeightDesktop;
margin-top: -#{$topHeightDesktop};
}
}
diff --git a/src/remark-plugins/remark-remove-heading-id/__snapshots__/index.test.mjs.snap b/src/remark-plugins/remark-remove-heading-id/__snapshots__/index.test.mjs.snap
new file mode 100644
index 000000000000..02e066d7ceb0
--- /dev/null
+++ b/src/remark-plugins/remark-remove-heading-id/__snapshots__/index.test.mjs.snap
@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`customize blockquote should add id 1`] = `
+"
hello world
+this is me.
+"
+`;
diff --git a/src/remark-plugins/remark-remove-heading-id/index.mjs b/src/remark-plugins/remark-remove-heading-id/index.mjs
new file mode 100644
index 000000000000..fe4df6e0b8ec
--- /dev/null
+++ b/src/remark-plugins/remark-remove-heading-id/index.mjs
@@ -0,0 +1,14 @@
+import { visit } from 'unist-util-visit';
+export default function () {
+ return function transformer(ast) {
+ visit(ast, 'heading', visitor);
+ };
+ function visitor(node) {
+ if (node.data && node.data.id) {
+ delete node.data.id;
+ }
+ if (node.data && node.data.hProperties && node.data.hProperties.id) {
+ delete node.data.hProperties.id;
+ }
+ }
+}
diff --git a/src/remark-plugins/remark-remove-heading-id/index.test.mjs b/src/remark-plugins/remark-remove-heading-id/index.test.mjs
new file mode 100644
index 000000000000..1782ce1c2676
--- /dev/null
+++ b/src/remark-plugins/remark-remove-heading-id/index.test.mjs
@@ -0,0 +1,23 @@
+import { remark } from 'remark';
+import remarkHtml from 'remark-html';
+import Plugin from './index.mjs';
+import remarkSlug from '../remark-slug/index.mjs';
+describe('customize blockquote', () => {
+ it('should add id', () => {
+ remark()
+ .use(remarkSlug)
+ .use(Plugin)
+ .use(remarkHtml)
+ .process(
+ `
+## hello world
+
+this is me.
+`,
+ function (err, { value: contents }) {
+ expect(err).toBeNull();
+ expect(contents).toMatchSnapshot();
+ }
+ );
+ });
+});
diff --git a/src/remark-plugins/remark-slug/__snapshots__/index.test.mjs.snap b/src/remark-plugins/remark-slug/__snapshots__/index.test.mjs.snap
new file mode 100644
index 000000000000..16c03e73a1c9
--- /dev/null
+++ b/src/remark-plugins/remark-slug/__snapshots__/index.test.mjs.snap
@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`remark slug should add id 1`] = `
+"hello world
+this is me.
+"
+`;
diff --git a/src/remark-plugins/remark-slug/index.mjs b/src/remark-plugins/remark-slug/index.mjs
new file mode 100644
index 000000000000..79fdaef2aa23
--- /dev/null
+++ b/src/remark-plugins/remark-slug/index.mjs
@@ -0,0 +1,56 @@
+// based on https://github.com/remarkjs/remark-slug/blob/8e6394c3dd6232cc9f0fb0b05e7eaf33063effa5/index.js
+// to fix https://github.com/webpack/webpack.js.org/pull/5947
+/**
+ * @typedef {import('mdast').Root} Root
+ * @typedef {import('hast').Properties} Properties
+ */
+
+import { toString } from 'mdast-util-to-string';
+import { visit } from 'unist-util-visit';
+import BananaSlug from 'github-slugger';
+
+const slugs = new BananaSlug();
+
+/**
+ * Plugin to add anchors headings using GitHub’s algorithm.
+ *
+ * @type {import('unified').Plugin}
+ */
+export default function remarkSlug() {
+ return (tree) => {
+ slugs.reset();
+
+ visit(tree, 'heading', (node) => {
+ const data = node.data || (node.data = {});
+ const props = /** @type {Properties} */ (
+ data.hProperties || (data.hProperties = {})
+ );
+ let id = props.id;
+
+ id = id ? slugs.slug(String(id), true) : slugs.slug(toString(node));
+
+ data.id = id;
+ props.id = id;
+
+ // insert for headings
+ node.children = [
+ {
+ type: 'paragraph',
+ data: {
+ hName: 'span',
+ hProperties: {
+ id,
+ },
+ },
+ children: [
+ {
+ type: 'text',
+ value: '',
+ },
+ ],
+ },
+ ...node.children,
+ ];
+ });
+ };
+}
diff --git a/src/remark-plugins/remark-slug/index.test.mjs b/src/remark-plugins/remark-slug/index.test.mjs
new file mode 100644
index 000000000000..02eaa9eb64c4
--- /dev/null
+++ b/src/remark-plugins/remark-slug/index.test.mjs
@@ -0,0 +1,20 @@
+import { remark } from 'remark';
+import remarkHtml from 'remark-html';
+import Plugin from './index.mjs';
+describe('remark slug', () => {
+ it('should add id', () => {
+ remark()
+ .use(Plugin)
+ .use(remarkHtml)
+ .process(
+ `## hello world
+
+this is me.
+`,
+ function (err, { value: contents }) {
+ expect(err).toBeNull();
+ expect(contents).toMatchSnapshot();
+ }
+ );
+ });
+});
diff --git a/src/remark-plugins/remark-slug/license b/src/remark-plugins/remark-slug/license
new file mode 100644
index 000000000000..32e7a3d93ca5
--- /dev/null
+++ b/src/remark-plugins/remark-slug/license
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2015 Titus Wormer
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/utilities/content-tree-enhancers.mjs b/src/utilities/content-tree-enhancers.mjs
index b9c18e3fd7bc..47ac93f68f75 100644
--- a/src/utilities/content-tree-enhancers.mjs
+++ b/src/utilities/content-tree-enhancers.mjs
@@ -2,12 +2,13 @@ import fs from 'fs';
import path from 'path';
import frontMatter from 'front-matter';
import {remark} from 'remark';
-import slug from 'remark-slug';
+import slug from '../../src/remark-plugins/remark-slug/index.mjs';
import extractAnchors from 'remark-extract-anchors';
import remarkHtml from 'remark-html';
import frontmatter from 'remark-frontmatter';
import gfm from 'remark-gfm';
import emoji from 'remark-emoji';
+import remarkRemoveHeadingId from '../remark-plugins/remark-remove-heading-id/index.mjs';
export const enhance = (tree, options) => {
// delete `./` root directory on node
@@ -46,6 +47,7 @@ export const enhance = (tree, options) => {
.use(gfm)
.use(emoji)
.use(extractAnchors, { anchors, levels: 3 })
+ .use(remarkRemoveHeadingId)
.use(remarkHtml)
.process(content, (err) => {
if (err) {
diff --git a/webpack.common.mjs b/webpack.common.mjs
index b8cb05ccbb47..8dd46af61d30 100644
--- a/webpack.common.mjs
+++ b/webpack.common.mjs
@@ -4,7 +4,7 @@ import webpack from 'webpack';
import h from 'hastscript';
import remarkResponsiveTable from './src/remark-plugins/remark-responsive-table/remark-responsive-table.mjs';
import gfm from 'remark-gfm';
-import slug from 'remark-slug';
+import slug from './src/remark-plugins/remark-slug/index.mjs';
import cleanup from './src/remark-plugins/remark-cleanup-readme/index.mjs';
import aside from './src/remark-plugins/remark-custom-asides/index.mjs';
import autolink from 'remark-autolink-headings';
@@ -13,6 +13,7 @@ import frontmatter from 'remark-frontmatter';
import { createRequire } from 'module';
import remarkEmoji from 'remark-emoji';
import { fileURLToPath } from 'url';
+import remarkRemoveHeadingId from './src/remark-plugins/remark-remove-heading-id/index.mjs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@@ -44,6 +45,7 @@ const mdPlugins = [
},
],
refractor,
+ remarkRemoveHeadingId
];
export default ({ ssg = false }) => ({
diff --git a/yarn.lock b/yarn.lock
index 453a58289f36..5c99d1814fa4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2486,7 +2486,7 @@
dependencies:
"@types/node" "*"
-"@types/hast@^2.0.0", "@types/hast@^2.3.2":
+"@types/hast@^2.0.0":
version "2.3.4"
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc"
integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==
@@ -4857,11 +4857,6 @@ emittery@^0.8.1:
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860"
integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==
-"emoji-regex@>=6.0.0 <=6.1.1":
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e"
- integrity sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4=
-
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@@ -5849,12 +5844,10 @@ gifwrap@^0.9.2:
image-q "^1.1.1"
omggif "^1.0.10"
-github-slugger@^1.0.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.3.0.tgz#9bd0a95c5efdfc46005e82a906ef8e2a059124c9"
- integrity sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==
- dependencies:
- emoji-regex ">=6.0.0 <=6.1.1"
+github-slugger@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.4.0.tgz#206eb96cdb22ee56fdc53a28d5a302338463444e"
+ integrity sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==
glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
@@ -8297,7 +8290,7 @@ mdast-util-to-string@^2.0.0:
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b"
integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==
-mdast-util-to-string@^3.0.0:
+mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9"
integrity sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==
@@ -10351,18 +10344,6 @@ remark-refractor@montogeek/remark-refractor:
refractor "^3.1.0"
unist-util-visit "1.3.1"
-remark-slug@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/remark-slug/-/remark-slug-7.0.1.tgz#9827ce6d6ee81ca82b79891b0e5931a8123ce63b"
- integrity sha512-NRvYePr69LdeCkEGwL4KYAmq7kdWG5rEavCXMzUR4qndLoXHJAOLSUmPY6Qm4NJfKix7/EmgObyVaYivONAFhg==
- dependencies:
- "@types/hast" "^2.3.2"
- "@types/mdast" "^3.0.0"
- github-slugger "^1.0.0"
- mdast-util-to-string "^3.0.0"
- unified "^10.0.0"
- unist-util-visit "^4.0.0"
-
remark-squeeze-paragraphs@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz#76eb0e085295131c84748c8e43810159c5653ead"