From 11ac939bc3d86fefafcc940da98df0e402455672 Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Thu, 4 Jul 2024 17:22:57 +0200 Subject: [PATCH] Add `rehype-twoslash` * check most examples with typescript * add special twoslash directives to code blocks so that twoslash understand partial examples * add dependencies for these examples, so typescript can check them * remove theme-ui docs here, their site has info, link to it --- docs/_asset/index.css | 86 +- docs/_asset/index.js | 62 +- docs/blog/index.mdx | 4 +- docs/blog/v3.mdx | 4 +- docs/community/index.mdx | 4 +- docs/docs/extending-mdx.mdx | 4 +- docs/docs/getting-started.mdx | 271 ++-- docs/docs/index.mdx | 4 +- docs/docs/troubleshooting-mdx.mdx | 44 +- docs/docs/using-mdx.mdx | 206 ++- docs/docs/what-is-mdx.mdx | 4 +- docs/guides/embed.mdx | 22 +- docs/guides/frontmatter.mdx | 22 +- docs/guides/gfm.mdx | 9 +- docs/guides/index.mdx | 4 +- docs/guides/injecting-components.mdx | 43 +- docs/guides/math.mdx | 9 +- docs/guides/mdx-on-demand.mdx | 35 +- docs/guides/syntax-highlighting.mdx | 55 +- docs/migrating/v2.mdx | 2 +- docs/packages/index.mdx | 4 +- package-lock.json | 2100 +++++++++++++++++++++----- package.json | 11 + packages/loader/readme.md | 18 +- packages/preact/readme.md | 6 +- packages/react/readme.md | 6 +- packages/rollup/readme.md | 12 +- tsconfig.json | 1 + website/mdx-config.js | 54 +- 29 files changed, 2424 insertions(+), 682 deletions(-) diff --git a/docs/_asset/index.css b/docs/_asset/index.css index 7a3d35912..f84762d9a 100644 --- a/docs/_asset/index.css +++ b/docs/_asset/index.css @@ -297,7 +297,6 @@ pre code { } pre code, -.hljs, .frame-body, .frame-tab-item-selected { background-color: #fafafa !important; /* Color from one-light */ @@ -583,7 +582,6 @@ button.success { .navigation .icon { display: block; - vertical-align: middle; width: auto; height: calc(1em + 1ex); } @@ -660,9 +658,6 @@ button.success { padding-inline-start: calc(0.5 * (1em + 1ex)); } -.nav-description { -} - .skip-to-navigation { inset-block-start: 0; inset-inline-start: 0; @@ -837,11 +832,13 @@ button.success { overflow-y: auto; } -.frame-tab-bar + pre { +.frame-tab-bar + pre, +.frame-tab-bar + .highlight > pre { margin-block-start: 0; } -.frame-tab-bar + pre code { +.frame-tab-bar + pre code, +.frame-tab-bar + .highlight > pre code { --squircle-radius: 0; border-top-left-radius: 0; border-top-right-radius: 0; @@ -946,6 +943,55 @@ details[open] { padding: calc(1em + 1ex); } +.rehype-twoslash-completion-deprecated { + opacity: 0.5; +} + +.rehype-twoslash-popover-target { + cursor: default; +} + +.highlight:is(:hover, :focus-within) .rehype-twoslash-popover-target { + background-color: var(--gray-2); +} + +/* Wavy underline for errors. */ +.rehype-twoslash-error-target { + background-repeat: repeat-x; + background-position: bottom left; + background-image: url('data:image/svg+xml,'); +} + +/* The content that will be shown in the tooltip. */ +.rehype-twoslash-popover { + position: absolute; + max-width: calc(45 * (1em + 1ex)); + padding: calc(0.5 * (1em + 1ex)); + margin: 0; + background-color: var(--bg); + border: 1px solid var(--gray-2); + border-radius: 3px; +} + +/* No padding if we have a padded code block (and perhaps more blocks) */ +.rehype-twoslash-popover:has(.rehype-twoslash-popover-code) { + padding: 0; +} + +.rehype-twoslash-popover-code { + margin: 0; +} + +.rehype-twoslash-popover-code > code { + mask-image: none; + border-radius: 0; +} + +.rehype-twoslash-popover-description { + background-color: var(--bg); + padding: 0 1em; +} + @media (prefers-color-scheme: dark) { :root { --white: #f0f6fc; @@ -1038,6 +1084,14 @@ details[open] { background-color: var(--gray-8); } + .highlight:is(:hover, :focus-within) .rehype-twoslash-popover-target { + background-color: var(--gray-5); + } + + .rehype-twoslash-popover { + border-color: var(--gray-6); + } + h6 { color: var(--gray-3); } @@ -1062,7 +1116,6 @@ details[open] { } pre code, - .hljs, .frame-body, .frame-tab-item-selected, .frame-tab-item-dark.frame-tab-item-selected { @@ -1231,23 +1284,6 @@ details[open] { } } -/* Fix a11y. */ -.hljs-built_in, -.hljs-symbol { - color: hsl(24deg 92% 40%) !important; -} - -@media (prefers-color-scheme: dark) { - .hljs-section { - color: #488bef !important; - } - - .hljs-built_in, - .hljs-symbol { - color: #ffa657 !important; - } -} - .playground { min-height: 40rem; gap: calc(1em + 1ex); diff --git a/docs/_asset/index.js b/docs/_asset/index.js index 2b4f9e2a1..d271c1118 100644 --- a/docs/_asset/index.js +++ b/docs/_asset/index.js @@ -1,5 +1,7 @@ +/* eslint-disable unicorn/prefer-query-selector */ /// +import {computePosition, shift} from '@floating-ui/dom' import copyToClipboard from 'copy-to-clipboard' import {ok as assert} from 'devlop' @@ -57,7 +59,35 @@ for (const copy of copies) { assert(copy instanceof HTMLButtonElement) copy.type = 'button' copy.replaceChildren(copyIcon.cloneNode(true)) - copy.addEventListener('click', onclick) + copy.addEventListener('click', oncopyonclick) +} + +const popoverTargets = /** @type {Array} */ ( + Array.from(document.querySelectorAll('.rehype-twoslash-popover-target')) +) + +for (const popoverTarget of popoverTargets) { + /** @type {NodeJS.Timeout | number} */ + let timeout = 0 + + popoverTarget.addEventListener('click', function () { + popoverShow(popoverTarget) + }) + + popoverTarget.addEventListener('mouseenter', function () { + clearTimeout(timeout) + timeout = setTimeout(function () { + popoverShow(popoverTarget) + }, 300) + }) + + popoverTarget.addEventListener('mouseleave', function () { + clearTimeout(timeout) + }) + + if (popoverTarget.classList.contains('rehype-twoslash-autoshow')) { + popoverShow(popoverTarget) + } } /** @@ -66,7 +96,7 @@ for (const copy of copies) { * @returns {undefined} * Nothing. */ -function onclick() { +function oncopyonclick() { assert(copyIcon) assert(copiedIcon) assert(this instanceof HTMLButtonElement) @@ -84,3 +114,31 @@ function onclick() { this.replaceChildren(copyIcon.cloneNode(true)) }, 2000) } + +/** + * @param {HTMLElement} popoverTarget + * Popover target. + * @returns {undefined} + * Nothing. + */ +function popoverShow(popoverTarget) { + const id = popoverTarget.dataset.popoverTarget + if (!id) return + const popover = document.getElementById(id) + if (!popover) return + + popover.showPopover() + + computePosition(popoverTarget, popover, { + placement: 'bottom', + middleware: [shift({padding: 5})] + }).then( + /** + * @param {{x: number, y: number}} value + */ + function (value) { + popover.style.left = value.x + 'px' + popover.style.top = value.y + 'px' + } + ) +} diff --git a/docs/blog/index.mdx b/docs/blog/index.mdx index 3b4ea79a3..e3053ac0e 100644 --- a/docs/blog/index.mdx +++ b/docs/blog/index.mdx @@ -1,6 +1,6 @@ { /** - * @import {Item} from '../_component/sort.js + * @import {Item} from '../_component/sort.js' */ /** @@ -14,7 +14,7 @@ import {BlogGroup} from '../_component/blog.jsx' export const info = { author: [{name: 'MDX Contributors'}], - modified: new Date('2021-11-01'), + modified: new Date('2024-07-04'), published: new Date('2021-11-01') } export const navExcludeGroup = true diff --git a/docs/blog/v3.mdx b/docs/blog/v3.mdx index 2a50c1845..89279eef8 100644 --- a/docs/blog/v3.mdx +++ b/docs/blog/v3.mdx @@ -58,9 +58,7 @@ technically breaking. We now accept block expressions right next to block JSX tags: -{/* Note: `language` because our theme doesn’t support it yet. */} - -```jsx chrome=no language="mdx" +```mdx chrome=no