mirror of
https://github.com/LukeHagar/unicorn-utterances.git
synced 2025-12-06 04:21:55 +00:00
feat: tabs can now contain custom IDs
This commit is contained in:
@@ -26,7 +26,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
transformIgnorePatterns: [
|
transformIgnorePatterns: [
|
||||||
// ...your ignore patterns
|
// ...your ignore patterns
|
||||||
"^((?!node_modules).)*node_modules.((?!unified|unist|hast|remark|mdast|micromark|retext|nlcst|rehype|decode-named-character-reference|character-entities|zwitch|longest-streak|unherit|parse-|strip-|html-void-elements|stringify-entities|ccount|markdown-|slash|vfile|property-|space-separated-|comma-separated-|web-namespaces|react-children-utilities|junk).)*$",
|
"^((?!node_modules).)*node_modules.((?!unified|unist|hast|remark|mdast|micromark|retext|nlcst|rehype|decode-named-character-reference|character-entities|zwitch|longest-streak|unherit|parse-|strip-|html-void-elements|stringify-entities|ccount|markdown-|slash|vfile|property-|space-separated-|comma-separated-|web-namespaces|junk).)*$",
|
||||||
"^.+\\.module\\.(css|sass|scss)$",
|
"^.+\\.module\\.(css|sass|scss)$",
|
||||||
],
|
],
|
||||||
// moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths),
|
// moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths),
|
||||||
|
|||||||
67
package-lock.json
generated
67
package-lock.json
generated
@@ -12,6 +12,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remark-embedder/core": "^2.0.0",
|
"@remark-embedder/core": "^2.0.0",
|
||||||
"@remark-embedder/transformer-oembed": "^2.0.0",
|
"@remark-embedder/transformer-oembed": "^2.0.0",
|
||||||
|
"@types/github-slugger": "^1.3.0",
|
||||||
|
"@types/lodash": "^4.14.179",
|
||||||
"batteries-not-included": "^0.1.0",
|
"batteries-not-included": "^0.1.0",
|
||||||
"classnames": "2.3.1",
|
"classnames": "2.3.1",
|
||||||
"copy-webpack-plugin": "^9.0.1",
|
"copy-webpack-plugin": "^9.0.1",
|
||||||
@@ -20,12 +22,13 @@
|
|||||||
"disqus-react": "^1.1.2",
|
"disqus-react": "^1.1.2",
|
||||||
"framer-motion": "^4.1.17",
|
"framer-motion": "^4.1.17",
|
||||||
"gatsby-remark-embedder": "^5.0.0",
|
"gatsby-remark-embedder": "^5.0.0",
|
||||||
|
"github-slugger": "^1.4.0",
|
||||||
"gray-matter": "4.0.3",
|
"gray-matter": "4.0.3",
|
||||||
"junk": "^4.0.0",
|
"junk": "^4.0.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"lunr": "^2.3.9",
|
"lunr": "^2.3.9",
|
||||||
"next": "^12.1.0",
|
"next": "^12.1.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-children-utilities": "^2.6.3",
|
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-medium-image-zoom": "^4.3.5",
|
"react-medium-image-zoom": "^4.3.5",
|
||||||
"react-paginate": "^8.0.3",
|
"react-paginate": "^8.0.3",
|
||||||
@@ -33,7 +36,7 @@
|
|||||||
"rehype-img-size": "github:unicorn-utterances/rehype-img-size#relative-path-full",
|
"rehype-img-size": "github:unicorn-utterances/rehype-img-size#relative-path-full",
|
||||||
"rehype-parse": "^8.0.3",
|
"rehype-parse": "^8.0.3",
|
||||||
"rehype-react": "^7.0.3",
|
"rehype-react": "^7.0.3",
|
||||||
"rehype-slug-custom-id": "^1.0.0",
|
"rehype-slug-custom-id": "^1.1.0",
|
||||||
"rehype-stringify": "^9.0.2",
|
"rehype-stringify": "^9.0.2",
|
||||||
"remark-behead": "^2.3.3",
|
"remark-behead": "^2.3.3",
|
||||||
"remark-gfm": "^3.0.1",
|
"remark-gfm": "^3.0.1",
|
||||||
@@ -86,7 +89,7 @@
|
|||||||
"lint-staged": "^12.1.2",
|
"lint-staged": "^12.1.2",
|
||||||
"next-compose-plugins": "^2.2.1",
|
"next-compose-plugins": "^2.2.1",
|
||||||
"next-sitemap": "^1.6.237",
|
"next-sitemap": "^1.6.237",
|
||||||
"prettier": "^2.5.0",
|
"prettier": "^2.5.1",
|
||||||
"react-test-renderer": "^17.0.2",
|
"react-test-renderer": "^17.0.2",
|
||||||
"ts-jest": "^27.1.1"
|
"ts-jest": "^27.1.1"
|
||||||
}
|
}
|
||||||
@@ -4014,6 +4017,11 @@
|
|||||||
"@types/ms": "*"
|
"@types/ms": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/github-slugger": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/github-slugger/-/github-slugger-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g=="
|
||||||
|
},
|
||||||
"node_modules/@types/graceful-fs": {
|
"node_modules/@types/graceful-fs": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||||
@@ -4087,6 +4095,11 @@
|
|||||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/lodash": {
|
||||||
|
"version": "4.14.179",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz",
|
||||||
|
"integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w=="
|
||||||
|
},
|
||||||
"node_modules/@types/lunr": {
|
"node_modules/@types/lunr": {
|
||||||
"version": "2.3.4",
|
"version": "2.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.3.4.tgz",
|
||||||
@@ -13262,9 +13275,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
|
||||||
"integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
|
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin-prettier.js"
|
"prettier": "bin-prettier.js"
|
||||||
@@ -13461,14 +13474,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-children-utilities": {
|
|
||||||
"version": "2.6.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-children-utilities/-/react-children-utilities-2.6.3.tgz",
|
|
||||||
"integrity": "sha512-ncP/JU26u/V8PyORIUzR2+yMb8YSGKLMbaqo9xwvQlNUAXMyUk2mja4torT7HKvGAzknMPR9Qnl2U6c7KD4kZw==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "17.x.x || 16.x.x || 15.x.x"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||||
@@ -13836,9 +13841,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rehype-slug-custom-id": {
|
"node_modules/rehype-slug-custom-id": {
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/rehype-slug-custom-id/-/rehype-slug-custom-id-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/rehype-slug-custom-id/-/rehype-slug-custom-id-1.1.0.tgz",
|
||||||
"integrity": "sha512-gt8KAAXLtH3Fd8zZrQZx8DZogLZImrHc0jjwQQoGYtXV8cnb5O2veSQ3ArwdgAFzzM9fC+bycWR8Qw39Z14NHA==",
|
"integrity": "sha512-lLdTHGd7u5bOXRDnD78/VHrVZsG63nN6lZUuQgcuupGt1+v+uDW7pCeQS0cvptRcZPYzg8B+0bf8sUiMBKsjZw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/hast": "^2.0.0",
|
"@types/hast": "^2.0.0",
|
||||||
"github-slugger": "^1.1.1",
|
"github-slugger": "^1.1.1",
|
||||||
@@ -19024,6 +19029,11 @@
|
|||||||
"@types/ms": "*"
|
"@types/ms": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/github-slugger": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/github-slugger/-/github-slugger-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g=="
|
||||||
|
},
|
||||||
"@types/graceful-fs": {
|
"@types/graceful-fs": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||||
@@ -19097,6 +19107,11 @@
|
|||||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/lodash": {
|
||||||
|
"version": "4.14.179",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz",
|
||||||
|
"integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w=="
|
||||||
|
},
|
||||||
"@types/lunr": {
|
"@types/lunr": {
|
||||||
"version": "2.3.4",
|
"version": "2.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.3.4.tgz",
|
||||||
@@ -25854,9 +25869,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
|
||||||
"integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
|
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"prettier-linter-helpers": {
|
"prettier-linter-helpers": {
|
||||||
@@ -26006,12 +26021,6 @@
|
|||||||
"object-assign": "^4.1.1"
|
"object-assign": "^4.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-children-utilities": {
|
|
||||||
"version": "2.6.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-children-utilities/-/react-children-utilities-2.6.3.tgz",
|
|
||||||
"integrity": "sha512-ncP/JU26u/V8PyORIUzR2+yMb8YSGKLMbaqo9xwvQlNUAXMyUk2mja4torT7HKvGAzknMPR9Qnl2U6c7KD4kZw==",
|
|
||||||
"requires": {}
|
|
||||||
},
|
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||||
@@ -26294,9 +26303,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rehype-slug-custom-id": {
|
"rehype-slug-custom-id": {
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/rehype-slug-custom-id/-/rehype-slug-custom-id-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/rehype-slug-custom-id/-/rehype-slug-custom-id-1.1.0.tgz",
|
||||||
"integrity": "sha512-gt8KAAXLtH3Fd8zZrQZx8DZogLZImrHc0jjwQQoGYtXV8cnb5O2veSQ3ArwdgAFzzM9fC+bycWR8Qw39Z14NHA==",
|
"integrity": "sha512-lLdTHGd7u5bOXRDnD78/VHrVZsG63nN6lZUuQgcuupGt1+v+uDW7pCeQS0cvptRcZPYzg8B+0bf8sUiMBKsjZw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/hast": "^2.0.0",
|
"@types/hast": "^2.0.0",
|
||||||
"github-slugger": "^1.1.1",
|
"github-slugger": "^1.1.1",
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remark-embedder/core": "^2.0.0",
|
"@remark-embedder/core": "^2.0.0",
|
||||||
"@remark-embedder/transformer-oembed": "^2.0.0",
|
"@remark-embedder/transformer-oembed": "^2.0.0",
|
||||||
|
"@types/github-slugger": "^1.3.0",
|
||||||
|
"@types/lodash": "^4.14.179",
|
||||||
"batteries-not-included": "^0.1.0",
|
"batteries-not-included": "^0.1.0",
|
||||||
"classnames": "2.3.1",
|
"classnames": "2.3.1",
|
||||||
"copy-webpack-plugin": "^9.0.1",
|
"copy-webpack-plugin": "^9.0.1",
|
||||||
@@ -42,12 +44,13 @@
|
|||||||
"disqus-react": "^1.1.2",
|
"disqus-react": "^1.1.2",
|
||||||
"framer-motion": "^4.1.17",
|
"framer-motion": "^4.1.17",
|
||||||
"gatsby-remark-embedder": "^5.0.0",
|
"gatsby-remark-embedder": "^5.0.0",
|
||||||
|
"github-slugger": "^1.4.0",
|
||||||
"gray-matter": "4.0.3",
|
"gray-matter": "4.0.3",
|
||||||
"junk": "^4.0.0",
|
"junk": "^4.0.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"lunr": "^2.3.9",
|
"lunr": "^2.3.9",
|
||||||
"next": "^12.1.0",
|
"next": "^12.1.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-children-utilities": "^2.6.3",
|
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-medium-image-zoom": "^4.3.5",
|
"react-medium-image-zoom": "^4.3.5",
|
||||||
"react-paginate": "^8.0.3",
|
"react-paginate": "^8.0.3",
|
||||||
@@ -55,7 +58,7 @@
|
|||||||
"rehype-img-size": "github:unicorn-utterances/rehype-img-size#relative-path-full",
|
"rehype-img-size": "github:unicorn-utterances/rehype-img-size#relative-path-full",
|
||||||
"rehype-parse": "^8.0.3",
|
"rehype-parse": "^8.0.3",
|
||||||
"rehype-react": "^7.0.3",
|
"rehype-react": "^7.0.3",
|
||||||
"rehype-slug-custom-id": "^1.0.0",
|
"rehype-slug-custom-id": "^1.1.0",
|
||||||
"rehype-stringify": "^9.0.2",
|
"rehype-stringify": "^9.0.2",
|
||||||
"remark-behead": "^2.3.3",
|
"remark-behead": "^2.3.3",
|
||||||
"remark-gfm": "^3.0.1",
|
"remark-gfm": "^3.0.1",
|
||||||
@@ -108,7 +111,7 @@
|
|||||||
"lint-staged": "^12.1.2",
|
"lint-staged": "^12.1.2",
|
||||||
"next-compose-plugins": "^2.2.1",
|
"next-compose-plugins": "^2.2.1",
|
||||||
"next-sitemap": "^1.6.237",
|
"next-sitemap": "^1.6.237",
|
||||||
"prettier": "^2.5.0",
|
"prettier": "^2.5.1",
|
||||||
"react-test-renderer": "^17.0.2",
|
"react-test-renderer": "^17.0.2",
|
||||||
"ts-jest": "^27.1.1"
|
"ts-jest": "^27.1.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
TabPanel as ReactTabPanel,
|
TabPanel as ReactTabPanel,
|
||||||
} from "react-tabs";
|
} from "react-tabs";
|
||||||
import { ReactElement, useCallback } from "react";
|
import { ReactElement, useCallback } from "react";
|
||||||
import { onlyText } from "react-children-utilities";
|
|
||||||
import { useIsomorphicLayoutEffect } from "react-use";
|
import { useIsomorphicLayoutEffect } from "react-use";
|
||||||
import { MarkdownDataContext } from "utils/markdown/MarkdownRenderer/data-context";
|
import { MarkdownDataContext } from "utils/markdown/MarkdownRenderer/data-context";
|
||||||
|
|
||||||
@@ -27,8 +26,7 @@ const Tabs: React.FC = ({ children }) => {
|
|||||||
return maybeTabComp?.type === ReactTab;
|
return maybeTabComp?.type === ReactTab;
|
||||||
})
|
})
|
||||||
.map((tabComp: ReactElement) => {
|
.map((tabComp: ReactElement) => {
|
||||||
// Contents of tab header
|
return tabComp.props["data-tabname"];
|
||||||
return onlyText(tabComp.props.children);
|
|
||||||
});
|
});
|
||||||
return tabTextArr as string[];
|
return tabTextArr as string[];
|
||||||
}, [children]);
|
}, [children]);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { parent } from "constants/site-config";
|
|||||||
import { rehypeHeaderText } from "./plugins/add-header-text";
|
import { rehypeHeaderText } from "./plugins/add-header-text";
|
||||||
import remarkTwoslash from "remark-shiki-twoslash";
|
import remarkTwoslash from "remark-shiki-twoslash";
|
||||||
import { UserConfigSettings } from "shiki-twoslash";
|
import { UserConfigSettings } from "shiki-twoslash";
|
||||||
import { rehypeTabs } from "utils/markdown/plugins/tabs";
|
import { rehypeTabs, RehypeTabsProps } from "utils/markdown/plugins/tabs";
|
||||||
import { PluggableList } from "unified";
|
import { PluggableList } from "unified";
|
||||||
|
|
||||||
// Optional now. Probably should move to an array that's passed or something
|
// Optional now. Probably should move to an array that's passed or something
|
||||||
@@ -76,7 +76,15 @@ export default async function markdownToHtml(
|
|||||||
dir: imgDirectory,
|
dir: imgDirectory,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
rehypeTabs,
|
[
|
||||||
|
rehypeTabs,
|
||||||
|
{
|
||||||
|
injectSubheaderProps: true,
|
||||||
|
tabSlugifyProps: {
|
||||||
|
enableCustomId: true,
|
||||||
|
},
|
||||||
|
} as RehypeTabsProps,
|
||||||
|
],
|
||||||
[
|
[
|
||||||
rehypeSlug,
|
rehypeSlug,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ test("headers are tabified", (done) => {
|
|||||||
.use(remarkParse)
|
.use(remarkParse)
|
||||||
.use(remarkStringify)
|
.use(remarkStringify)
|
||||||
.use(remarkToRehype, { allowDangerousHtml: true })
|
.use(remarkToRehype, { allowDangerousHtml: true })
|
||||||
.use(rehypeTabs)
|
.use(rehypeTabs, {})
|
||||||
.use(rehypeStringify, { allowDangerousHtml: true })
|
.use(rehypeStringify, { allowDangerousHtml: true })
|
||||||
.process(
|
.process(
|
||||||
`
|
`
|
||||||
@@ -33,14 +33,14 @@ Bonjour!
|
|||||||
function (err, file) {
|
function (err, file) {
|
||||||
expect(err).toBeNull();
|
expect(err).toBeNull();
|
||||||
expect(file?.value).toMatchInlineSnapshot(`
|
expect(file?.value).toMatchInlineSnapshot(`
|
||||||
"<tabs><tab-list><tab>English</tab><tab>French</tab><tab>Italian</tab></tab-list><tab-panel>
|
"<tabs><tab-list><tab data-tabname=\\"english\\">English</tab><tab data-tabname=\\"french\\">French</tab><tab data-tabname=\\"italian\\">Italian</tab></tab-list><tab-panel data-tabname=\\"english\\">
|
||||||
<p>Hello!</p>
|
<p>Hello!</p>
|
||||||
</tab-panel><tab-panel>
|
</tab-panel><tab-panel data-tabname=\\"french\\">
|
||||||
<p>Bonjour!</p>
|
<p>Bonjour!</p>
|
||||||
</tab-panel><tab-panel>
|
</tab-panel><tab-panel data-tabname=\\"italian\\">
|
||||||
<p>Bonjour!</p>
|
<p>Bonjour!</p>
|
||||||
<!-- tabs:end --></tab-panel></tabs>"
|
<!-- tabs:end --></tab-panel></tabs>"
|
||||||
`);
|
`);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -51,7 +51,7 @@ test("sub-headers are not tabified", (done) => {
|
|||||||
.use(remarkParse)
|
.use(remarkParse)
|
||||||
.use(remarkStringify)
|
.use(remarkStringify)
|
||||||
.use(remarkToRehype, { allowDangerousHtml: true })
|
.use(remarkToRehype, { allowDangerousHtml: true })
|
||||||
.use(rehypeTabs)
|
.use(rehypeTabs, {})
|
||||||
.use(rehypeStringify, { allowDangerousHtml: true })
|
.use(rehypeStringify, { allowDangerousHtml: true })
|
||||||
.process(
|
.process(
|
||||||
`
|
`
|
||||||
@@ -78,16 +78,16 @@ Bonjour!
|
|||||||
function (err, file) {
|
function (err, file) {
|
||||||
expect(err).toBeNull();
|
expect(err).toBeNull();
|
||||||
expect(file?.value).toMatchInlineSnapshot(`
|
expect(file?.value).toMatchInlineSnapshot(`
|
||||||
"<tabs><tab-list><tab>English</tab><tab>French</tab><tab>Italian</tab></tab-list><tab-panel>
|
"<tabs><tab-list><tab data-tabname=\\"english\\">English</tab><tab data-tabname=\\"french\\">French</tab><tab data-tabname=\\"italian\\">Italian</tab></tab-list><tab-panel data-tabname=\\"english\\">
|
||||||
<p>Hello!</p>
|
<p>Hello!</p>
|
||||||
<h5>A note about English</h5>
|
<h5>A note about English</h5>
|
||||||
<p>Something!</p>
|
<p>Something!</p>
|
||||||
</tab-panel><tab-panel>
|
</tab-panel><tab-panel data-tabname=\\"french\\">
|
||||||
<p>Bonjour!</p>
|
<p>Bonjour!</p>
|
||||||
</tab-panel><tab-panel>
|
</tab-panel><tab-panel data-tabname=\\"italian\\">
|
||||||
<p>Bonjour!</p>
|
<p>Bonjour!</p>
|
||||||
<!-- tabs:end --></tab-panel></tabs>"
|
<!-- tabs:end --></tab-panel></tabs>"
|
||||||
`);
|
`);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Root } from "hast";
|
import { Root } from "hast";
|
||||||
import replaceAllBetween from "unist-util-replace-all-between";
|
import replaceAllBetween from "unist-util-replace-all-between";
|
||||||
import { Node } from "unist";
|
import { Node } from "unist";
|
||||||
|
import { Plugin } from "unified";
|
||||||
|
import { getHeaderNodeId, slugs } from "rehype-slug-custom-id";
|
||||||
|
|
||||||
type ElementNode = Node & HTMLElement;
|
type ElementNode = Node & HTMLElement;
|
||||||
|
|
||||||
@@ -20,6 +22,11 @@ const findLargestHeading = (nodes: ElementNode[]) => {
|
|||||||
const isNodeLargestHeading = (n: ElementNode, largestSize: number) =>
|
const isNodeLargestHeading = (n: ElementNode, largestSize: number) =>
|
||||||
isNodeHeading(n) && parseInt(n.tagName.substr(1), 10) === largestSize;
|
isNodeHeading(n) && parseInt(n.tagName.substr(1), 10) === largestSize;
|
||||||
|
|
||||||
|
export interface RehypeTabsProps {
|
||||||
|
injectSubheaderProps?: boolean;
|
||||||
|
tabSlugifyProps?: Parameters<typeof getHeaderNodeId>[1];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin to add Docsify's tab support.
|
* Plugin to add Docsify's tab support.
|
||||||
* @see https://jhildenbiddle.github.io/docsify-tabs/
|
* @see https://jhildenbiddle.github.io/docsify-tabs/
|
||||||
@@ -37,8 +44,11 @@ const isNodeLargestHeading = (n: ElementNode, largestSize: number) =>
|
|||||||
* To align with React Tabs package:
|
* To align with React Tabs package:
|
||||||
* @see https://github.com/reactjs/react-tabs
|
* @see https://github.com/reactjs/react-tabs
|
||||||
*/
|
*/
|
||||||
export const rehypeTabs = () => {
|
export const rehypeTabs: Plugin<[RehypeTabsProps | never], Root> = ({
|
||||||
return (tree: Root) => {
|
injectSubheaderProps = false,
|
||||||
|
tabSlugifyProps = {},
|
||||||
|
}) => {
|
||||||
|
return (tree) => {
|
||||||
replaceAllBetween(
|
replaceAllBetween(
|
||||||
tree,
|
tree,
|
||||||
{ type: "raw", value: "<!-- tabs:start -->" } as never,
|
{ type: "raw", value: "<!-- tabs:start -->" } as never,
|
||||||
@@ -70,16 +80,29 @@ export const rehypeTabs = () => {
|
|||||||
sectionStarted = true;
|
sectionStarted = true;
|
||||||
|
|
||||||
if (isNodeLargestHeading(localNode, largestSize)) {
|
if (isNodeLargestHeading(localNode, largestSize)) {
|
||||||
|
// Make sure that all tabs labeled "thing" aren't also labeled "thing2"
|
||||||
|
slugs.reset();
|
||||||
|
const { id: headerSlug } = getHeaderNodeId(
|
||||||
|
localNode,
|
||||||
|
tabSlugifyProps
|
||||||
|
);
|
||||||
|
|
||||||
const header = {
|
const header = {
|
||||||
type: "element",
|
type: "element",
|
||||||
tagName: "tab",
|
tagName: "tab",
|
||||||
children: localNode.children,
|
children: localNode.children,
|
||||||
|
properties: {
|
||||||
|
"data-tabname": headerSlug,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const contents = {
|
const contents = {
|
||||||
type: "element",
|
type: "element",
|
||||||
tagName: "tab-panel",
|
tagName: "tab-panel",
|
||||||
children: [],
|
children: [],
|
||||||
|
properties: {
|
||||||
|
"data-tabname": headerSlug,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
tabsContainer.children[0].children.push(header);
|
tabsContainer.children[0].children.push(header);
|
||||||
@@ -88,6 +111,10 @@ export const rehypeTabs = () => {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isNodeHeading(localNode) && injectSubheaderProps) {
|
||||||
|
// localNode
|
||||||
|
}
|
||||||
|
|
||||||
// Push into last `tab-panel`
|
// Push into last `tab-panel`
|
||||||
tabsContainer.children[
|
tabsContainer.children[
|
||||||
tabsContainer.children.length - 1
|
tabsContainer.children.length - 1
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ test("tabs should render", () => {
|
|||||||
markdownHTML: `
|
markdownHTML: `
|
||||||
<tabs>
|
<tabs>
|
||||||
<tab-list>
|
<tab-list>
|
||||||
<tab>Header</tab>
|
<tab data-tabname="header">Header</tab>
|
||||||
<tab>Header2</tab>
|
<tab data-tabname="header2">Header2</tab>
|
||||||
</tab-list>
|
</tab-list>
|
||||||
<tab-panel>Hello</tab-panel>
|
<tab-panel data-tabname="header">Hello</tab-panel>
|
||||||
<tab-panel>Goodbye</tab-panel>
|
<tab-panel data-tabname="header2">Goodbye</tab-panel>
|
||||||
</tabs>
|
</tabs>
|
||||||
`,
|
`,
|
||||||
}}
|
}}
|
||||||
@@ -45,11 +45,11 @@ test("tabs should persist", () => {
|
|||||||
markdownHTML: `
|
markdownHTML: `
|
||||||
<tabs>
|
<tabs>
|
||||||
<tab-list>
|
<tab-list>
|
||||||
<tab>Header</tab>
|
<tab data-tabname="header">Header</tab>
|
||||||
<tab>Header2</tab>
|
<tab data-tabname="header2">Header2</tab>
|
||||||
</tab-list>
|
</tab-list>
|
||||||
<tab-panel>Hello</tab-panel>
|
<tab-panel data-tabname="header">Hello</tab-panel>
|
||||||
<tab-panel>Goodbye</tab-panel>
|
<tab-panel data-tabname="header2">Goodbye</tab-panel>
|
||||||
</tabs>
|
</tabs>
|
||||||
`,
|
`,
|
||||||
}}
|
}}
|
||||||
@@ -76,20 +76,20 @@ test("tabs should sync values", () => {
|
|||||||
markdownHTML: `
|
markdownHTML: `
|
||||||
<tabs>
|
<tabs>
|
||||||
<tab-list>
|
<tab-list>
|
||||||
<tab>Header</tab>
|
<tab data-tabname="header">Header</tab>
|
||||||
<tab>Header2</tab>
|
<tab data-tabname="header2">Header2</tab>
|
||||||
</tab-list>
|
</tab-list>
|
||||||
<tab-panel>Hello</tab-panel>
|
<tab-panel data-tabname="header">Hello</tab-panel>
|
||||||
<tab-panel>Goodbye</tab-panel>
|
<tab-panel data-tabname="header2">Goodbye</tab-panel>
|
||||||
</tabs>
|
</tabs>
|
||||||
|
|
||||||
<tabs>
|
<tabs>
|
||||||
<tab-list>
|
<tab-list>
|
||||||
<tab>Header</tab>
|
<tab data-tabname="header">Header</tab>
|
||||||
<tab>Header2</tab>
|
<tab data-tabname="header2">Header2</tab>
|
||||||
</tab-list>
|
</tab-list>
|
||||||
<tab-panel>Hello2</tab-panel>
|
<tab-panel data-tabname="header">Hello2</tab-panel>
|
||||||
<tab-panel>Goodbye2</tab-panel>
|
<tab-panel data-tabname="header2">Goodbye2</tab-panel>
|
||||||
</tabs>
|
</tabs>
|
||||||
`,
|
`,
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user