diff --git a/packages/mdx/dev/content/comment-annotations.mdx b/packages/mdx/dev/content/comment-annotations.mdx index 11f87ce0..05970d10 100644 --- a/packages/mdx/dev/content/comment-annotations.mdx +++ b/packages/mdx/dev/content/comment-annotations.mdx @@ -93,3 +93,21 @@ function lorem(ipsum, dolor = 1) { return $sit and consectetur(ipsum) or [] } ``` + +With class + +```js +function lorem(ipsum, dolor = 1) { + // withClass[15:19] annotation-class + const sit = ipsum == null && 0 + // withClass(1:2) annotation-class + dolor = sit - amet(dolor) + return sit ? consectetur(ipsum) : [] +} + +function adipiscing(...elit) { + console.log("hover me") + // withClass annotation-class + return elit.map(ipsum => ipsum.sit) +} +``` diff --git a/packages/mdx/dev/content/copy-button.mdx b/packages/mdx/dev/content/copy-button.mdx new file mode 100644 index 00000000..807108a6 --- /dev/null +++ b/packages/mdx/dev/content/copy-button.mdx @@ -0,0 +1,59 @@ +one line: + +```js +const x = 2 +``` + +no editor: + +```js +function foo() { + return 2 +} +``` + +one file editor: + +```js foo.js +function foo() { + return 2 +} +``` + +two files: + + + +```js foo.js +function foo() { + return 2 +} +``` + +```js bar.js +function bar() { + return 2 +} +``` + + + +two panels: + + + +```js foo.js +function foo() { + return 2 +} +``` + +--- + +```js bar.js +function bar() { + return 2 +} +``` + + diff --git a/packages/mdx/dev/files.ts b/packages/mdx/dev/files.ts index 29a2479d..626effcf 100644 --- a/packages/mdx/dev/files.ts +++ b/packages/mdx/dev/files.ts @@ -1,7 +1,7 @@ import fs from "fs" import { remarkCodeHike } from "../src/index" import { compile } from "@mdx-js/mdx" -import theme from "shiki/themes/nord.json" +import theme from "shiki/themes/github-light.json" import { withDebugger } from "mdx-debugger" export async function getFiles() { @@ -19,7 +19,7 @@ export async function getContent(filename: string) { return file } -export async function getCode(file: string) { +export async function getCode(file: string, config = {}) { let debugLink = "" const debugCompile = withDebugger(compile, { @@ -32,7 +32,15 @@ export async function getCode(file: string) { await debugCompile(file, { outputFormat: "function-body", remarkPlugins: [ - [remarkCodeHike, { autoImport: false, theme }], + [ + remarkCodeHike, + { + autoImport: false, + showCopyButton: true, + theme, + ...config, + }, + ], ], }) ) diff --git a/packages/mdx/dev/layout.tsx b/packages/mdx/dev/layout.tsx new file mode 100644 index 00000000..17477c11 --- /dev/null +++ b/packages/mdx/dev/layout.tsx @@ -0,0 +1,73 @@ +import Link from "next/link" +import Head from "next/head" + +const extraItems = ["themes"] + +export function Layout({ + children, + current, + contentFileNames, + style = {}, +}) { + return ( +
+ + Code Hike Test - {current} + + + +
+ {children} +
+
+ ) +} + +function Sidebar({ contentFileNames, current }) { + const items = contentFileNames.concat(extraItems) + return ( + + ) +} diff --git a/packages/mdx/package.json b/packages/mdx/package.json index e961fbaa..6b1b2fea 100644 --- a/packages/mdx/package.json +++ b/packages/mdx/package.json @@ -59,6 +59,7 @@ "@types/node-fetch": "^2.6.1", "@types/react": "^17.0.39", "autoprefixer": "^9.8.2", + "click-to-react-component": "^1.0.8", "cssnano": "^4.1.10", "diff": "^4.0.2", "esbuild": "^0.13.2", diff --git a/packages/mdx/pages/[name].tsx b/packages/mdx/pages/[name].tsx index ae4c52be..caf7b48e 100644 --- a/packages/mdx/pages/[name].tsx +++ b/packages/mdx/pages/[name].tsx @@ -1,9 +1,9 @@ import { runSync } from "@mdx-js/mdx" import * as runtime from "react/jsx-runtime.js" import { CH } from "../src/components" -import Link from "next/link" import { getCode, getContent, getFiles } from "../dev/files" -import Head from "next/head" +import { ClickToComponent } from "click-to-react-component" +import { Layout } from "../dev/layout" export async function getStaticPaths() { const files = await getFiles() @@ -37,63 +37,7 @@ export default function Page({ }) { const { default: Content } = runSync(code, runtime) return ( -
- - Code Hike Test - {current} - - - -
- ) -} - -function Sidebar({ tests, current }) { - return ( - - ) -} - -function Result({ Content, debugLink }) { - return ( -
+ -
+ ) } diff --git a/packages/mdx/pages/compile.tsx b/packages/mdx/pages/compile.tsx deleted file mode 100644 index e4002fc0..00000000 --- a/packages/mdx/pages/compile.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { compile } from "@mdx-js/mdx" -import { runSync } from "@mdx-js/mdx" -import * as runtime from "react/jsx-runtime.js" -import { remarkCodeHike } from "../src/index" -import { CH } from "../src/components" -import fs from "node:fs" - -export async function getServerSideProps() { - const source = fs.readFileSync( - "./tests/scrollycoding.mdx", - "utf8" - ) - const code = String( - await compile(source, { - outputFormat: "function-body", - remarkPlugins: [ - [remarkCodeHike, { autoImport: false }], - ], - }) - ) - return { - props: { - title: "Home", - code, - }, - } -} - -export default function Page({ title, code }) { - const { default: Content } = runSync(code, runtime) - return ( -
-

{title}

- -
- ) -} diff --git a/packages/mdx/pages/evaluate.tsx b/packages/mdx/pages/evaluate.tsx deleted file mode 100644 index 76ca7825..00000000 --- a/packages/mdx/pages/evaluate.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { compile } from "@mdx-js/mdx" -import { runSync, evaluateSync } from "@mdx-js/mdx" -import * as runtime from "react/jsx-runtime.js" -import { remarkCodeHike } from "../src/index" -import { CH } from "../src/components" -import fs from "node:fs" - -export async function getServerSideProps() { - const source = fs.readFileSync( - "./tests/scrollycoding.mdx", - "utf8" - ) - const code = String( - await compile(source, { - outputFormat: "function-body", - remarkPlugins: [ - [remarkCodeHike, { autoImport: false }], - ], - }) - ) - return { - props: { - title: "Home", - source, - code, - }, - } -} - -export default function Page({ title, code, source }) { - // const { default: Content } = evaluateSync(source, { - // ...runtime, - // remarkPlugins: [ - // [remarkCodeHike, { autoImport: false }], - // ], - // } as any) - - const { default: Content } = runSync(code, runtime) - return ( -
-

{title}

- -
- ) -} diff --git a/packages/mdx/pages/styles.css b/packages/mdx/pages/styles.css index 40188c83..e15a5db6 100644 --- a/packages/mdx/pages/styles.css +++ b/packages/mdx/pages/styles.css @@ -33,113 +33,6 @@ div#__next > div { color: black; } -/* -nav { - height: 40px; - overflow: hidden; +.annotation-class span { + text-decoration: line-through; } - -main { - flex: 1; - overflow: auto; -} */ - -/* main */ -/* -.columns { - display: flex; - min-height: 100%; -} - -.column { - margin-left: auto; - margin-right: auto; - flex: 1; - box-sizing: border-box; - padding: 0 6px 6px; - min-width: 400px; - max-width: 800px; -} - -.column > h2 { - padding: 6px; - margin: 0; - text-align: center; - font-size: 20px; - color: #ccc; -} - -.column > .content { - padding: 10px 18px; - background-color: #fff; - border-radius: 6px; -} - - -nav { - display: flex; - align-items: center; - background-color: #222; - color: #ccc; -} - -nav h1 { - margin: 0 16px 0 24px; -} -nav h1 a { - color: unset; - text-decoration: none; -} - -nav .version { - color: #aaa; - font-size: 14px; -} - -.radio { - text-align: center; - border: 1px solid #222; - border-radius: 4px; - overflow: hidden; - display: inline-block; - vertical-align: middle; - margin-left: 6px; -} -.radio button { - border: none; - background-color: #444; - color: #ccc; - height: 24px; -} -.radio button.selected { - background-color: #fafafa; - color: #222; -} - -nav label { - margin-right: 24px; -} */ - -/* nav select { - margin-left: 6px; - border-radius: 4px; - background-color: #fafafa; - height: 24px; -} */ - -/* result */ -/* -.result { - min-width: 900px; - width: 900px; - max-width: 900px; -} - -pre.shiki { - white-space: pre-wrap; -} - -.tailwind-font code { - font-family: ui-monospace, SFMono-Regular, Consolas, - "Liberation Mono", Menlo, monospace; -} */ diff --git a/packages/mdx/pages/themes.tsx b/packages/mdx/pages/themes.tsx new file mode 100644 index 00000000..848f34c0 --- /dev/null +++ b/packages/mdx/pages/themes.tsx @@ -0,0 +1,85 @@ +import { BUNDLED_THEMES } from "shiki" +import { getCode, getFiles } from "../dev/files" +import * as runtime from "react/jsx-runtime.js" +import { runSync } from "@mdx-js/mdx" +import { CH } from "../src/components" +import { Layout } from "../dev/layout" + +const mdx = ` + + +~~~js foo.js +function foo(x = 1) { + return "bar" +} +~~~ +--- +~~~css foo.css +body { + height: 32px; +} +~~~ + + +~~~py +def foo(x = 1): + return "bar" +~~~ +` + +export async function getStaticProps() { + const files = await getFiles() + const promises = BUNDLED_THEMES.filter( + x => x !== "css-variables" + ).map(async themeName => { + const theme = ( + await import(`shiki/themes/${themeName}.json`) + ).default + const { code } = await getCode(mdx, { + theme, + lineNumbers: true, + showCopyButton: true, + }) + return { themeName, code } + }) + + const codes = await Promise.all(promises) + + return { + props: { + tests: files, + codes, + }, + } +} + +export default function Page({ codes, tests }) { + const components = codes.map(({ code }) => { + return runSync(code, runtime).default + }) + return ( + +
+ {components.map((Content, i) => ( +
+

{codes[i].themeName}

+ +
+ ))} +
+
+ ) +} diff --git a/packages/mdx/src/mdx-client/annotations.tsx b/packages/mdx/src/mdx-client/annotations.tsx index c6a50af3..69e589e6 100644 --- a/packages/mdx/src/mdx-client/annotations.tsx +++ b/packages/mdx/src/mdx-client/annotations.tsx @@ -15,6 +15,7 @@ export const annotationsMap: Record< label: Label, link: CodeLink, mark: Mark, + withClass: WithClass, } function Mark({ @@ -97,6 +98,25 @@ function Box({ ) } +function WithClass({ + children, + data, + style, + theme, +}: { + data: any + children: React.ReactNode + style?: React.CSSProperties + theme: any +}) { + const className = data as string + return ( + + {children} + + ) +} + function Background({ children, data, diff --git a/packages/mdx/src/mdx-plugin/plugin.ts b/packages/mdx/src/mdx-plugin/plugin.ts index e5550b3a..427e6b1e 100644 --- a/packages/mdx/src/mdx-plugin/plugin.ts +++ b/packages/mdx/src/mdx-plugin/plugin.ts @@ -15,6 +15,7 @@ type CodeHikeConfig = { theme: any lineNumbers?: boolean autoImport?: boolean + showCopyButton?: boolean } export function remarkCodeHike( diff --git a/packages/mdx/src/mini-editor/editor-frame.tsx b/packages/mdx/src/mini-editor/editor-frame.tsx index 409788f9..cb2c4a60 100644 --- a/packages/mdx/src/mini-editor/editor-frame.tsx +++ b/packages/mdx/src/mini-editor/editor-frame.tsx @@ -30,7 +30,8 @@ type EditorFrameProps = { theme: EditorTheme terminalPanel?: React.ReactNode height?: number - button?: React.ReactNode + northButton?: React.ReactNode + southButton?: React.ReactNode classes?: Classes onTabClick?: (filename: string) => void } & React.PropsWithoutRef @@ -45,7 +46,8 @@ export const EditorFrame = React.forwardRef< terminalPanel, style, height, - button, + northButton, + southButton, theme, className, onTabClick, @@ -66,11 +68,16 @@ export const EditorFrame = React.forwardRef< ...style, }} > -
+
), }, + southContent: getContentFromFile(nextSouthFile), southPanel: inputSouthPanel && { tabs: southTabs!, style: southStyle!, @@ -162,6 +167,7 @@ function startingPosition( } = getStepFiles(prev, next, true) return { + northContent: getContentFromFile(prevNorthFile), northPanel: { tabs: inputNorthPanel.tabs.map(title => ({ title, @@ -182,6 +188,7 @@ function startingPosition( /> ), }, + southContent: getContentFromFile(prevSouthFile), southPanel: inputSouthPanel && { tabs: inputSouthPanel.tabs.map(title => ({ title, @@ -229,6 +236,7 @@ function endingPosition( } return { + northContent: getContentFromFile(nextNorthFile), northPanel: { tabs: inputNorthPanel.tabs.map(title => ({ title, @@ -249,6 +257,7 @@ function endingPosition( /> ), }, + southContent: getContentFromFile(nextSouthFile), southPanel: inputSouthPanel && { tabs: inputSouthPanel.tabs.map(title => ({ title, @@ -305,6 +314,10 @@ function CodeTransition({ ) } +function getContentFromFile(file?: CodeFile) { + return file ? codeToText(file.code) : "" +} + /** * Get the StepFiles for a transition * in each panel, if the prev and next active files are the same diff --git a/packages/mdx/src/mini-editor/editor-tween.tsx b/packages/mdx/src/mini-editor/editor-tween.tsx index 8f2add33..ced8dc5a 100644 --- a/packages/mdx/src/mini-editor/editor-tween.tsx +++ b/packages/mdx/src/mini-editor/editor-tween.tsx @@ -7,6 +7,7 @@ import { TerminalPanel } from "./terminal-panel" import { useTransition, EditorStep } from "./editor-shift" import { CodeConfig } from "../smooth-code" import { useLayoutEffect } from "../utils" +import { CopyButton } from "smooth-code/copy-button" export { EditorTransition, EditorTween } export type { EditorTransitionProps, EditorTweenProps } @@ -53,13 +54,20 @@ function EditorTween({ ...divProps }: EditorTweenProps) { const ref = React.createRef() - const { northPanel, southPanel } = useTransition( + + const { showCopyButton, ...config } = codeConfig + const { + northPanel, + southPanel, + northContent, + southContent, + } = useTransition( ref, prev, next || prev, t, backward, - codeConfig + config ) const [frozenHeight, freezeHeight] = React.useState< @@ -102,6 +110,22 @@ function EditorTween({ southPanel={southPanel} terminalPanel={terminalPanel} theme={codeConfig.theme} + northButton={ + showCopyButton ? ( + + ) : undefined + } + southButton={ + showCopyButton ? ( + + ) : undefined + } /> ) } diff --git a/packages/mdx/src/smooth-code/code-tween.tsx b/packages/mdx/src/smooth-code/code-tween.tsx index 4aa3c0f0..fd0e7271 100644 --- a/packages/mdx/src/smooth-code/code-tween.tsx +++ b/packages/mdx/src/smooth-code/code-tween.tsx @@ -17,6 +17,7 @@ import { CodeShift, } from "./partial-step-parser" import { SmoothLines } from "./smooth-lines" +import { CopyButton } from "./copy-button" type HTMLProps = React.DetailedHTMLProps< React.HTMLAttributes, @@ -43,6 +44,7 @@ export type CodeConfig = { horizontalCenter?: boolean theme: IRawTheme lineNumbers?: boolean + showCopyButton?: boolean } function useCodeShift({ @@ -132,6 +134,7 @@ function AfterDimensions({ stepInfo, progress, htmlProps, + config, }: { dimensions: NonNullable stepInfo: CodeShift @@ -140,6 +143,7 @@ function AfterDimensions({ htmlProps: HTMLProps }) { const { bg, fg } = getCodeColors(theme) + return ( + {config.showCopyButton ? ( + + ) : undefined} ) } @@ -183,6 +199,7 @@ function Wrapper({ style={{ margin: 0, padding: 0, + position: "relative", // using this instead of
 because https://github.com/code-hike/codehike/issues/120
         whiteSpace: "pre",
         ...style,
diff --git a/packages/mdx/src/smooth-code/copy-button.tsx b/packages/mdx/src/smooth-code/copy-button.tsx
new file mode 100644
index 00000000..7209907c
--- /dev/null
+++ b/packages/mdx/src/smooth-code/copy-button.tsx
@@ -0,0 +1,84 @@
+import React from "react"
+
+export function CopyButton({
+  content,
+  style,
+}: {
+  content: string
+  style?: React.CSSProperties
+}) {
+  const [copied, setCopied] = React.useState(false)
+
+  return (
+     {
+        copyToClipboard(content)
+        setCopied(true)
+        setTimeout(() => {
+          setCopied(false)
+        }, 1200)
+      }}
+      className="ch-copy-button"
+      fill="none"
+      stroke="currentColor"
+      viewBox="0 0 24 24"
+      xmlns="http://www.w3.org/2000/svg"
+    >
+      Copy
+
+      {copied ? (
+        
+      ) : (
+        
+      )}
+    
+  )
+}
+
+function copyToClipboard(text: string) {
+  if (!navigator.clipboard) {
+    fallbackCopyTextToClipboard(text)
+    return
+  }
+  navigator.clipboard.writeText(text)
+}
+
+function fallbackCopyTextToClipboard(text: string) {
+  var textArea = document.createElement("textarea")
+  textArea.value = text
+
+  // Avoid scrolling to bottom
+  textArea.style.top = "0"
+  textArea.style.left = "0"
+  textArea.style.position = "fixed"
+
+  document.body.appendChild(textArea)
+  textArea.focus()
+  textArea.select()
+
+  try {
+    var successful = document.execCommand("copy")
+    // var msg = successful ? "successful" : "unsuccessful"
+    // console.log("Fallback: Copying text command was " + msg)
+  } catch (err) {
+    // console.error("Fallback: Oops, unable to copy", err)
+  }
+
+  document.body.removeChild(textArea)
+}
diff --git a/packages/mdx/src/utils/code.ts b/packages/mdx/src/utils/code.ts
index 6522ccf1..f98cc73a 100644
--- a/packages/mdx/src/utils/code.ts
+++ b/packages/mdx/src/utils/code.ts
@@ -11,3 +11,11 @@ export type Code = {
   lines: HighlightedLine[]
   lang: string
 }
+
+export function codeToText(code: Code) {
+  return code.lines
+    .map(line =>
+      line.tokens.map(token => token.content).join("")
+    )
+    .join("\n")
+}
diff --git a/packages/mdx/src/utils/theme.ts b/packages/mdx/src/utils/theme.ts
index 94c6d5de..ff555bdb 100644
--- a/packages/mdx/src/utils/theme.ts
+++ b/packages/mdx/src/utils/theme.ts
@@ -45,6 +45,7 @@ export enum ColorName {
   InputBackground,
   InputBorder,
   SelectionBackground,
+  IconForeground,
 }
 
 type Color = string | undefined
@@ -200,6 +201,15 @@ export function getColor(
           hc: "#f3f518",
         })
       )
+    case ColorName.IconForeground:
+      return (
+        colors["icon.foreground"] ||
+        getDefault(theme, {
+          dark: "#C5C5C5",
+          light: "#424242",
+          hc: "#FFFFFF",
+        })
+      )
     default:
       return "#f00"
   }
diff --git a/yarn.lock b/yarn.lock
index b7d27789..6bf227c5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1925,6 +1925,36 @@
   resolved "https://registry.yarnpkg.com/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz#c05ed35ad82df8e6ac616c68b92c2282bd083ba4"
   integrity sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==
 
+"@floating-ui/core@^0.6.2":
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-0.6.2.tgz#f2813f0e5f3d5ed7af5029e1a082203dadf02b7d"
+  integrity sha512-jktYRmZwmau63adUG3GKOAVCofBXkk55S/zQ94XOorAHhwqFIOFAy1rSp2N0Wp6/tGbe9V3u/ExlGZypyY17rg==
+
+"@floating-ui/dom@^0.4.5":
+  version "0.4.5"
+  resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-0.4.5.tgz#2e88d16646119cc67d44683f75ee99840475bbfa"
+  integrity sha512-b+prvQgJt8pieaKYMSJBXHxX/DYwdLsAWxKYqnO5dO2V4oo/TYBZJAUQCVNjTWWsrs6o4VDrNcP9+E70HAhJdw==
+  dependencies:
+    "@floating-ui/core" "^0.6.2"
+
+"@floating-ui/react-dom-interactions@^0.3.1":
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/@floating-ui/react-dom-interactions/-/react-dom-interactions-0.3.1.tgz#abc0cb4b18e6f095397e50f9846572eee4e34554"
+  integrity sha512-tP2KEh7EHJr5hokSBHcPGojb+AorDNUf0NYfZGg/M+FsMvCOOsSEeEF0O1NDfETIzDnpbHnCs0DuvCFhSMSStg==
+  dependencies:
+    "@floating-ui/react-dom" "^0.6.3"
+    aria-hidden "^1.1.3"
+    point-in-polygon "^1.1.0"
+    use-isomorphic-layout-effect "^1.1.1"
+
+"@floating-ui/react-dom@^0.6.3":
+  version "0.6.3"
+  resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-0.6.3.tgz#7b64cfd4fd12e4a0515dbf1b2be16e48c9a06c5a"
+  integrity sha512-hC+pS5D6AgS2wWjbmSQ6UR6Kpy+drvWGJIri6e1EDGADTPsCaa4KzCgmCczHrQeInx9tqs81EyDmbKJYY2swKg==
+  dependencies:
+    "@floating-ui/dom" "^0.4.5"
+    use-isomorphic-layout-effect "^1.1.1"
+
 "@gar/promisify@^1.0.1":
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
@@ -4445,6 +4475,13 @@ argparse@^2.0.1:
   resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
   integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
 
+aria-hidden@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.1.3.tgz#bb48de18dc84787a3c6eee113709c473c64ec254"
+  integrity sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==
+  dependencies:
+    tslib "^1.0.0"
+
 array-back@^3.0.1, array-back@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
@@ -5343,6 +5380,15 @@ cli-width@^3.0.0:
   resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
   integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
 
+click-to-react-component@^1.0.8:
+  version "1.0.8"
+  resolved "https://registry.yarnpkg.com/click-to-react-component/-/click-to-react-component-1.0.8.tgz#bcad2f4551dde67c54cec77e02791c7ecda50e5a"
+  integrity sha512-YBNYOp00udy+NBEnUmM/3Df0Yco1iHNQ8k0ltlJVcDYK9AuYt14xPoJicBh/BokLqbzkci1p+pbdY5r4JXZC4g==
+  dependencies:
+    "@floating-ui/react-dom-interactions" "^0.3.1"
+    htm "^3.1.0"
+    react-merge-refs "^1.1.0"
+
 clipanion@^3.2.0-rc.10:
   version "3.2.0-rc.11"
   resolved "https://registry.yarnpkg.com/clipanion/-/clipanion-3.2.0-rc.11.tgz#765661c9aeda8ecc14035a61a4b19b361f9a5400"
@@ -8896,6 +8942,11 @@ hsla-regex@^1.0.0:
   resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38"
   integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg=
 
+htm@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/htm/-/htm-3.1.1.tgz#49266582be0dc66ed2235d5ea892307cc0c24b78"
+  integrity sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==
+
 html-entities@^2.3.2:
   version "2.3.3"
   resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46"
@@ -12478,6 +12529,11 @@ pkg-up@^3.1.0:
   dependencies:
     find-up "^3.0.0"
 
+point-in-polygon@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/point-in-polygon/-/point-in-polygon-1.1.0.tgz#b0af2616c01bdee341cbf2894df643387ca03357"
+  integrity sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==
+
 portfinder@^1.0.28:
   version "1.0.28"
   resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778"
@@ -13537,6 +13593,11 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1:
   dependencies:
     "@babel/runtime" "^7.10.3"
 
+react-merge-refs@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-1.1.0.tgz#73d88b892c6c68cbb7a66e0800faa374f4c38b06"
+  integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==
+
 react-refresh@^0.11.0:
   version "0.11.0"
   resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046"
@@ -15551,7 +15612,7 @@ tslib@2.1.0:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
   integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
 
-tslib@^1.14.1, tslib@^1.9.0:
+tslib@^1.0.0, tslib@^1.14.1, tslib@^1.9.0:
   version "1.14.1"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
@@ -16058,6 +16119,11 @@ use-isomorphic-layout-effect@^1.0.0:
   resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225"
   integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==
 
+use-isomorphic-layout-effect@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
+  integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
+
 use-latest@^1.0.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232"