diff --git a/packages/example-nextjs14/src/app/(demo)/CodeBlocksNext.tsx b/packages/example-nextjs14/src/app/(demo)/CodeBlocksNext.tsx
index 62a8814..ecddc70 100644
--- a/packages/example-nextjs14/src/app/(demo)/CodeBlocksNext.tsx
+++ b/packages/example-nextjs14/src/app/(demo)/CodeBlocksNext.tsx
@@ -1,5 +1,3 @@
-'use client';
-
import { File } from '../components/File';
import { CodeBlockState } from './CodeBlockState';
import { tooltips } from './tooltips';
diff --git a/packages/example-nextjs14/src/app/(demo)/page.tsx b/packages/example-nextjs14/src/app/(demo)/page.tsx
index bcee7a7..dce15df 100644
--- a/packages/example-nextjs14/src/app/(demo)/page.tsx
+++ b/packages/example-nextjs14/src/app/(demo)/page.tsx
@@ -1,17 +1,8 @@
-import dynamicImport from 'next/dynamic';
-import React from 'react';
import { DemoPart } from '../DemoPart';
import { Description } from '../components/Description';
import { TabsBlock } from './TabsBlock';
-
-const CodeBlocks = dynamicImport(
- () => import('./CodeBlocksNext')
- .then((mod) => mod.CodeBlocks),
- {
- loading: () =>
,
- },
-);
+import { CodeBlocks } from './CodeBlocksNext';
export default async function Home({ searchParams }: { searchParams: object }) {
return (
diff --git a/packages/example-nextjs14/src/app/(demo)/react-router/CodeBlocksRR.tsx b/packages/example-nextjs14/src/app/(demo)/react-router/CodeBlocksRR.tsx
index 136dcdb..5d8efe7 100644
--- a/packages/example-nextjs14/src/app/(demo)/react-router/CodeBlocksRR.tsx
+++ b/packages/example-nextjs14/src/app/(demo)/react-router/CodeBlocksRR.tsx
@@ -1,5 +1,3 @@
-'use client';
-
import { File } from '../../components/File';
import { CodeBlockState } from '../CodeBlockState';
import { tooltips } from '../tooltips';
diff --git a/packages/example-nextjs14/src/app/(demo)/react-router/page.tsx b/packages/example-nextjs14/src/app/(demo)/react-router/page.tsx
index a77b8f8..d228315 100644
--- a/packages/example-nextjs14/src/app/(demo)/react-router/page.tsx
+++ b/packages/example-nextjs14/src/app/(demo)/react-router/page.tsx
@@ -1,16 +1,8 @@
-import dynamicImport from 'next/dynamic';
-import React from 'react';
import { DemoPart } from '../../DemoPart';
import { Description } from '../../components/Description';
import { TabsBlock } from '../TabsBlock';
-
-const CodeBlocks = dynamicImport(
- () => import('./CodeBlocksRR').then((mod) => mod.CodeBlocksRR),
- {
- loading: () => ,
- },
-);
+import { CodeBlocksRR } from './CodeBlocksRR';
export default async function Home({ searchParams }: { searchParams: object }) {
return (
@@ -20,7 +12,7 @@ export default async function Home({ searchParams }: { searchParams: object }) {
diff --git a/packages/example-nextjs14/src/app/components/Code.tsx b/packages/example-nextjs14/src/app/components/Code.tsx
index 9713ccb..a62e74f 100644
--- a/packages/example-nextjs14/src/app/components/Code.tsx
+++ b/packages/example-nextjs14/src/app/components/Code.tsx
@@ -1,18 +1,15 @@
-'use client'
-import React from 'react';
+'use server'
import { highlight } from '../highlighter';
import { Langs } from '../types';
-export const Code = ({ content, lang, ...rest }: { content: string, lang?: Langs } & React.ComponentPropsWithoutRef<'div'>) => {
+export const Code = async ({ content, lang, id, ...rest }: { content: string, lang?: Langs, id?: string } & React.ComponentPropsWithoutRef<'div'>) => {
+ const text = await highlight(content, { lang })
- const [text, setText] = React.useState('');
-
- React.useEffect(() => {
- highlight(content, { lang }).then(setText)
- }, [content, lang])
-
- return text ?
-
- : {content.split('\n').map((el, ind) => (
{el || '_'}
))}
+ return {text ?
+
+ :
{content.split('\n')
+ .map((el, ind) => (
{el || '_'}
))}
+
}
+
}
diff --git a/packages/example-nextjs14/src/app/components/FakeTypes.tsx b/packages/example-nextjs14/src/app/components/FakeTypes.tsx
new file mode 100644
index 0000000..5e4f776
--- /dev/null
+++ b/packages/example-nextjs14/src/app/components/FakeTypes.tsx
@@ -0,0 +1,74 @@
+'use client';
+
+import React from 'react';
+
+import { useFloating, autoUpdate, useClientPoint, offset } from '@floating-ui/react';
+
+import { type Matcher, type Tooltip, type Langs } from '../types';
+import { highlight } from '../highlighter';
+
+export const FakeTypes = ({ matchers, id }: { matchers?: Matcher[], id: string }) => {
+ const [tooltip, setTooltip] = React.useState<{ x: number, y: number, nodes: Tooltip[] }>({ nodes: [], x: 0, y: 0 });
+
+ const { refs, floatingStyles, context } = useFloating({
+ whileElementsMounted: autoUpdate,
+ placement: 'top',
+ middleware: [
+ offset({ mainAxis: 20, crossAxis: 50 })
+ ]
+ });
+ useClientPoint(context,
+ { x: tooltip.x, y: tooltip.y }
+ )
+
+ React.useEffect(() => {
+ const codeBlock = document.querySelector(`[id="${id}"]`)
+
+ if (codeBlock && !(codeBlock as HTMLDivElement).onmouseover) {
+ const matchTooltips = (ev: MouseEvent) => {
+ // @ts-expect-error fots
+ const text = (ev?.target?.textContent || '').trim();
+ // @ts-expect-error fots
+ const next = (ev?.target?.nextSibling?.textContent || '').trim()
+
+ // if (text?.length < 12) {
+ // console.log(`${text}${next}`, { ev, context })
+ // }
+
+ const match = matchers?.find(el => el[0] === `${text}${next}`)
+
+ if (match) {
+ if (match[1] !== tooltip.nodes) {
+ setTooltip({ nodes: match[1], x: ev.clientX, y: ev.clientY })
+ }
+ } else if (tooltip.nodes.length) {
+ setTooltip(curr => ({ ...curr, nodes: [] }))
+ }
+ }
+
+ (codeBlock as HTMLDivElement).onmousemove = matchTooltips;
+ (codeBlock as HTMLDivElement).onmouseleave = () => setTooltip(curr => ({...curr, nodes: []}));
+
+ }
+ }, [id, tooltip.nodes, matchers])
+
+ return tooltip.nodes.length ?
+ {tooltip.nodes.map((node, ind) => (
+
+ ))}
+
: null
+}
+
+const CodeClient = ({ content, lang }: { content: string, lang?: Langs, id?: string }) => {
+ const [text, setText] = React.useState('');
+
+ React.useEffect(() => {
+ highlight(content, { lang }).then(setText)
+ }, [content, lang])
+
+ return
+}
diff --git a/packages/example-nextjs14/src/app/components/File.tsx b/packages/example-nextjs14/src/app/components/File.tsx
index 546ce66..3644c59 100644
--- a/packages/example-nextjs14/src/app/components/File.tsx
+++ b/packages/example-nextjs14/src/app/components/File.tsx
@@ -1,10 +1,17 @@
-'use client'
-import React from 'react';
-
-import { useFloating, autoUpdate, useClientPoint, offset } from '@floating-ui/react';
+import dynamicImport from 'next/dynamic';
import { Code } from './Code';
-import { type Matcher, type Tooltip } from '../types';
+import { type Matcher } from '../types';
+
+import { stringToHash } from '../utils';
+
+const FakeTypes = dynamicImport(
+ () => import('./FakeTypes')
+ .then((mod) => mod.FakeTypes),
+ {
+ loading: () => null,
+ },
+);
export const File = ({
name,
@@ -15,39 +22,7 @@ export const File = ({
content: string;
matchers?: Matcher[]
}) => {
- const [tooltip, setTooltip] = React.useState<{ x: number, y: number, nodes: Tooltip[] }>({ nodes: [], x: 0, y: 0 });
-
- const { refs, floatingStyles, context } = useFloating({
- whileElementsMounted: autoUpdate,
- placement: 'top',
- middleware: [
- offset({ mainAxis: 20, crossAxis: 50 })
- ]
- });
- useClientPoint(context,
- { x: tooltip.x, y: tooltip.y }
- )
-
- const matchTooltips = (ev: React.MouseEvent) => {
- // @ts-expect-error fots
- const text = (ev?.target?.textContent || '').trim();
- // @ts-expect-error fots
- const next = (ev?.target?.nextSibling?.textContent || '').trim()
-
- // if (text?.length < 12) {
- // console.log(`${text}${next}`, { ev, context })
- // }
-
- const match = matchers?.find(el => el[0] === `${text}${next}`)
-
- if (match) {
- if (match[1] !== tooltip.nodes) {
- setTooltip({ nodes: match[1], x: ev.clientX, y: ev.clientY })
- }
- } else if (tooltip.nodes.length) {
- setTooltip(curr => ({ ...curr, nodes: [] }))
- }
- }
+ const id = stringToHash(content);
return (
- {tooltip.nodes.length ?
- {tooltip.nodes.map((node, ind) => (
-
- ))}
-
: null}
-
-
+
-
-
-
+
);
diff --git a/packages/example-nextjs14/src/app/highlighter.ts b/packages/example-nextjs14/src/app/highlighter.ts
index 6c12adc..84790e7 100644
--- a/packages/example-nextjs14/src/app/highlighter.ts
+++ b/packages/example-nextjs14/src/app/highlighter.ts
@@ -65,3 +65,4 @@ function getHighlighter() {
})
}
+const _warmUp = getHighlighter()
diff --git a/packages/example-nextjs14/src/app/utils.ts b/packages/example-nextjs14/src/app/utils.ts
new file mode 100644
index 0000000..390c6cc
--- /dev/null
+++ b/packages/example-nextjs14/src/app/utils.ts
@@ -0,0 +1,13 @@
+export function stringToHash(text: string) {
+ let hash = 0;
+
+ if (text.length == 0) return '0';
+
+ for (let i = 0; i < text.length; i++) {
+ const char = text.charCodeAt(i);
+ hash = ((hash << 5) - hash) + char;
+ hash = hash & hash;
+ }
+
+ return String(hash);
+}