import { PortableText as BasePortableText, PortableTextMarkComponentProps, PortableTextProps, } from '@portabletext/react' import {PortableTextNode} from '@sanity/tsdoc' import {Box, Card, Code} from '@sanity/ui' import {MouseEvent, useCallback} from 'react' import {useTSDoc} from '../app' import {H, Level, P, useSpace, useTextSize} from '../lib/ui' const CODE_LANGUAGES: Record = { sh: 'bash', tsx: 'typescript', ts: 'typescript', } export function PortableText(props: {blocks: PortableTextNode[]}): React.ReactNode { const {blocks} = props return } const components: PortableTextProps['components'] = { block: { blockquote: BlockquoteBlock, h1: H1Block, h2: H2Block, h3: H3Block, h4: H4Block, h5: H5Block, h6: H6Block, normal: NormalBlock, }, types: { code: CodeBlock, }, marks: { link: Link, }, } function CodeBlock(props: {value: {code?: string; language?: string}}) { const {code, language = 'typescript'} = props.value return ( {code} ) } function H1Block({children}: {children?: React.ReactNode}) { return {children} } function H2Block({children}: {children?: React.ReactNode}) { return ( {children} ) } function H3Block({children}: {children?: React.ReactNode}) { return ( {children} ) } function H4Block({children}: {children?: React.ReactNode}) { return ( {children} ) } function H5Block({children}: {children?: React.ReactNode}) { return ( {children} ) } function H6Block({children}: {children?: React.ReactNode}) { return ( {children} ) } function BlockquoteBlock({children}: {children?: React.ReactNode}) { return (

{children}

) } function NormalBlock({children}: {children?: React.ReactNode}) { return (

{children}

) } function isValidUrl(url: string) { try { return Boolean(new URL(url)) } catch (error) { return false } } function getInternalHref({ url, packageName, exportPath, }: { url: string packageName: string | null exportPath?: string | null }) { const urlSegments = url.split('/') // URL can be of two types: // if it's referencing the same package then it will just have the name // if it's referencing another package then it will also have the exportPath in the name if (urlSegments.length === 1) { // exportPath is either `.` or `./router` return `/${packageName}${exportPath?.replace('.', '')}/${url}` } return `/${packageName}/${urlSegments.join('/')}` } function Link(props: PortableTextMarkComponentProps) { const {basePath, onPathChange, params} = useTSDoc() const {value, text} = props const {packageName, exportPath} = params const url = value?.['href'] const isExternalUrl = isValidUrl(url) const path = !isExternalUrl && getInternalHref({url, packageName, exportPath}) const href = isExternalUrl ? url : `${basePath}${path}` const handleClick = useCallback( (e: MouseEvent) => { // If the url is pointing to external URL don't call onPathChange if (isExternalUrl || !path) return e.preventDefault() // When calling onPathChange we need to call it without the basePath onPathChange(path) }, [isExternalUrl, onPathChange, path], ) return ( {text} ) }