From 3f760f17b9ede2e5cc4a31e1b5ed032321b5e29e Mon Sep 17 00:00:00 2001 From: raymondanythings Date: Sun, 1 Jun 2025 20:36:50 +0900 Subject: [PATCH 1/4] fix: improve image block link handling logic and add URL validation --- .../src/components/asset-wrapper.tsx | 68 ++++++++++++------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/packages/react-notion-x/src/components/asset-wrapper.tsx b/packages/react-notion-x/src/components/asset-wrapper.tsx index ef50f400c..8c46776b5 100644 --- a/packages/react-notion-x/src/components/asset-wrapper.tsx +++ b/packages/react-notion-x/src/components/asset-wrapper.tsx @@ -1,5 +1,9 @@ import type * as React from 'react' -import { type BaseContentBlock, type Block } from 'notion-types' +import { + type BaseContentBlock, + type Block, + type ImageBlock +} from 'notion-types' import { parsePageId } from 'notion-utils' import { useNotionContext } from '..' @@ -19,18 +23,11 @@ export function AssetWrapper({ const value = block as BaseContentBlock const { components, mapPageUrl, rootDomain, zoom } = useNotionContext() - let isURL = false - if (block.type === 'image') { - const caption: string | undefined = value?.properties?.caption?.[0]?.[0] - if (caption) { - const id = parsePageId(caption, { uuid: true }) + const caption = value.properties?.caption?.[0]?.[0] + const imageHyperlink = (value as ImageBlock).format?.image_hyperlink - const isPage = caption.charAt(0) === '/' && id - if (isPage || isValidURL(caption)) { - isURL = true - } - } - } + const availableLinks = [imageHyperlink, caption].filter(Boolean) as string[] + const urlInfo = getURL(value, availableLinks) const figure = (
- - {value?.properties?.caption && !isURL && ( + + {value?.properties?.caption && (
@@ -52,20 +49,14 @@ export function AssetWrapper({ ) // allows for an image to be a link - if (isURL) { - const caption: string | undefined = value?.properties?.caption?.[0]?.[0] - const id = parsePageId(caption, { uuid: true }) - const isPage = caption?.charAt(0) === '/' && id - const captionHostname = extractHostname(caption) - + if (urlInfo?.url) { + const urlHostName = extractHostname(urlInfo.url) return ( Date: Mon, 2 Jun 2025 07:08:01 +0900 Subject: [PATCH 2/4] fix: add image hyperlink format to ImageBlock and refactor URL handling in AssetWrapper --- packages/notion-types/src/block.ts | 3 ++ .../src/components/asset-wrapper.tsx | 32 +++++++++---------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/notion-types/src/block.ts b/packages/notion-types/src/block.ts index 48140b8cd..141e92b83 100644 --- a/packages/notion-types/src/block.ts +++ b/packages/notion-types/src/block.ts @@ -277,6 +277,9 @@ export interface ToggleBlock extends BaseBlock { export interface ImageBlock extends BaseContentBlock { type: 'image' + format: { + image_hyperlink: string + } & BaseContentBlock['format'] } export interface EmbedBlock extends BaseContentBlock { diff --git a/packages/react-notion-x/src/components/asset-wrapper.tsx b/packages/react-notion-x/src/components/asset-wrapper.tsx index 8c46776b5..646350428 100644 --- a/packages/react-notion-x/src/components/asset-wrapper.tsx +++ b/packages/react-notion-x/src/components/asset-wrapper.tsx @@ -11,6 +11,12 @@ import { cs } from '../utils' import { Asset } from './asset' import { Text } from './text' +interface URLInfo { + id?: string + type: 'page' | 'external' + url: string +} + const urlStyle = { width: '100%' } export function AssetWrapper({ @@ -27,7 +33,7 @@ export function AssetWrapper({ const imageHyperlink = (value as ImageBlock).format?.image_hyperlink const availableLinks = [imageHyperlink, caption].filter(Boolean) as string[] - const urlInfo = getURL(value, availableLinks) + const urlInfo = getURLInfo(value, availableLinks) const figure = (
{figure} @@ -69,14 +75,10 @@ export function AssetWrapper({ return figure } -function getURL( +function getURLInfo( block: BaseContentBlock, availableLinks: string[] -): { - id?: string - type: 'page' | 'external' - url: string -} | null { +): URLInfo | null { if (block.type !== 'image') { return null } @@ -84,7 +86,7 @@ function getURL( for (const link of availableLinks) { if (!link) continue - const id = parsePageId(link, { uuid: true }) + const id = parsePageId(link, { uuid: false }) const isPage = link.charAt(0) === '/' && id if (isPage || isValidURL(link)) { @@ -97,7 +99,6 @@ function getURL( } return null } - function isValidURL(str: string) { // TODO: replace this with a more well-tested package const pattern = new RegExp( @@ -111,7 +112,6 @@ function isValidURL(str: string) { ) return !!pattern.test(str) } - function extractHostname(url?: string) { try { const hostname = new URL(url!).hostname From 6ebee9590e6a62cf5acc150b60910bc00126fc91 Mon Sep 17 00:00:00 2001 From: yonghyunyeob Date: Mon, 2 Jun 2025 09:04:52 +0900 Subject: [PATCH 3/4] refactor: streamline URL handling in AssetWrapper by consolidating link logic and improving null checks --- .../src/components/asset-wrapper.tsx | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/packages/react-notion-x/src/components/asset-wrapper.tsx b/packages/react-notion-x/src/components/asset-wrapper.tsx index 646350428..7dbf18e81 100644 --- a/packages/react-notion-x/src/components/asset-wrapper.tsx +++ b/packages/react-notion-x/src/components/asset-wrapper.tsx @@ -1,4 +1,3 @@ -import type * as React from 'react' import { type BaseContentBlock, type Block, @@ -31,9 +30,9 @@ export function AssetWrapper({ const caption = value.properties?.caption?.[0]?.[0] const imageHyperlink = (value as ImageBlock).format?.image_hyperlink + const linkToUse = imageHyperlink || caption || '' - const availableLinks = [imageHyperlink, caption].filter(Boolean) as string[] - const urlInfo = getURLInfo(value, availableLinks) + const urlInfo = getURLInfo(value, linkToUse) const figure = (
Date: Mon, 2 Jun 2025 09:31:32 +0900 Subject: [PATCH 4/4] refactor: enhance URLInfo type definition and improve getURLInfo function logic for better clarity and validation --- .../src/components/asset-wrapper.tsx | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/packages/react-notion-x/src/components/asset-wrapper.tsx b/packages/react-notion-x/src/components/asset-wrapper.tsx index 7dbf18e81..c19954a67 100644 --- a/packages/react-notion-x/src/components/asset-wrapper.tsx +++ b/packages/react-notion-x/src/components/asset-wrapper.tsx @@ -10,12 +10,19 @@ import { cs } from '../utils' import { Asset } from './asset' import { Text } from './text' -interface URLInfo { - id?: string - type: 'page' | 'external' +interface PageInfo { + type: 'page' + id: string url: string } +interface ExternalInfo { + type: 'external' + url: string +} + +type URLInfo = PageInfo | ExternalInfo | null + const urlStyle = { width: '100%' } export function AssetWrapper({ @@ -77,27 +84,32 @@ export function AssetWrapper({ return figure } - -function getURLInfo(block: BaseContentBlock, link?: string): URLInfo | null { - if (!link) { +function getURLInfo(block: BaseContentBlock, link?: string): URLInfo { + if (!link || block.type !== 'image') { return null } - if (block.type !== 'image') { - return null - } const id = parsePageId(link, { uuid: true }) const isPage = link.charAt(0) === '/' && id - if (isPage || isValidURL(link)) { + if (isPage) { return { - id: id ?? undefined, - type: isValidURL(link) ? 'external' : 'page', + type: 'page' as const, + id, url: link } } + + if (isValidURL(link)) { + return { + type: 'external' as const, + url: link + } + } + return null } + function isValidURL(str: string) { // TODO: replace this with a more well-tested package const pattern = new RegExp(