From 12ac4056135f719fc26143e7fa903bdfc88a514e Mon Sep 17 00:00:00 2001 From: Cody Olsen Date: Wed, 19 Jun 2024 15:22:11 +0200 Subject: [PATCH] feat: add `react-compiler` export condition --- package.config.ts | 20 +++++++++- package.json | 8 +++- pnpm-lock.yaml | 42 ++++++++++---------- src/react-portable-text.tsx | 77 +++++++++++++++++++++++-------------- 4 files changed, 94 insertions(+), 53 deletions(-) diff --git a/package.config.ts b/package.config.ts index f19b08c..0e497bc 100644 --- a/package.config.ts +++ b/package.config.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import {defineConfig} from '@sanity/pkg-utils' import {visualizer} from 'rollup-plugin-visualizer' @@ -23,8 +24,25 @@ export default defineConfig({ }, babel: { - plugins: ['@babel/plugin-proposal-object-rest-spread'], + plugins: ['@babel/plugin-transform-object-rest-spread'], }, tsconfig: 'tsconfig.dist.json', + + reactCompilerOptions: { + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + console.group(`[${filename}] ${event.kind}`) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const {reason, description, severity, loc, suggestions} = event.detail as any + console.error(`[${severity}] ${reason}`) + console.log(`${filename}:${loc.start?.line}:${loc.start?.column} ${description}`) + console.log(suggestions) + + console.groupEnd() + } + }, + }, + }, }) diff --git a/package.json b/package.json index 1b0aee5..6ddd255 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@portabletext/react", - "version": "3.1.0", + "version": "3.1.0-canary.2", "description": "Render Portable Text with React", "keywords": [ "portable-text" @@ -20,6 +20,10 @@ "exports": { ".": { "source": "./src/index.ts", + "react-compiler": { + "source": "./src/index.ts", + "default": "./dist/index.compiled.js" + }, "import": "./dist/index.js", "require": "./dist/index.cjs", "default": "./dist/index.js" @@ -97,7 +101,7 @@ "@portabletext/types": "^2.0.13" }, "devDependencies": { - "@babel/plugin-proposal-object-rest-spread": "^7.20.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", "@sanity/pkg-utils": "^6.10.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b946a04..987439b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,9 +15,9 @@ importers: specifier: ^2.0.13 version: 2.0.13 devDependencies: - '@babel/plugin-proposal-object-rest-spread': - specifier: ^7.20.7 - version: 7.20.7(@babel/core@7.24.7) + '@babel/plugin-transform-object-rest-spread': + specifier: ^7.24.7 + version: 7.24.7(@babel/core@7.24.7) '@commitlint/cli': specifier: ^19.3.0 version: 19.3.0(@types/node@20.12.4)(typescript@5.4.5) @@ -256,13 +256,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-proposal-object-rest-spread@7.20.7': - resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-proposal-private-methods@7.18.6': resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} engines: {node: '>=6.9.0'} @@ -293,8 +286,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-parameters@7.24.1': - resolution: {integrity: sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==} + '@babel/plugin-transform-object-rest-spread@7.24.7': + resolution: {integrity: sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.24.7': + resolution: {integrity: sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -3718,15 +3717,6 @@ snapshots: dependencies: '@babel/types': 7.24.7 - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.24.7)': - dependencies: - '@babel/compat-data': 7.24.7 - '@babel/core': 7.24.7 - '@babel/helper-compilation-targets': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.7) - '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.24.7)': dependencies: '@babel/core': 7.24.7 @@ -3759,7 +3749,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.24.1(@babel/core@7.24.7)': + '@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.7) + + '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.24.7)': dependencies: '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 diff --git a/src/react-portable-text.tsx b/src/react-portable-text.tsx index f0b5723..68a503c 100644 --- a/src/react-portable-text.tsx +++ b/src/react-portable-text.tsx @@ -1,4 +1,8 @@ -import type {ToolkitNestedPortableTextSpan, ToolkitTextNode} from '@portabletext/toolkit' +import type { + ToolkitListNestMode, + ToolkitNestedPortableTextSpan, + ToolkitTextNode, +} from '@portabletext/toolkit' import { buildMarksTree, isPortableTextBlock, @@ -17,7 +21,7 @@ import type { PortableTextSpan, TypedObject, } from '@portabletext/types' -import {type ReactNode, useMemo} from 'react' +import {memo, type ReactNode, useMemo} from 'react' import {defaultComponents} from './components/defaults' import {mergeComponents} from './components/merge' @@ -39,26 +43,43 @@ import { unknownTypeWarning, } from './warnings' -export function PortableText({ - value: input, - components: componentOverrides, +export const PortableText = memo(function PortableTextComponent< + B extends TypedObject = PortableTextBlock, +>({ + value, + components, listNestingMode, onMissingComponent: missingComponentHandler = printWarning, }: PortableTextProps): JSX.Element { - const handleMissingComponent = missingComponentHandler || noop - const blocks = Array.isArray(input) ? input : [input] - const nested = nestLists(blocks, listNestingMode || LIST_NEST_MODE_HTML) - - const components = useMemo(() => { - return componentOverrides - ? mergeComponents(defaultComponents, componentOverrides) - : defaultComponents - }, [componentOverrides]) - const renderNode = useMemo( - () => getNodeRenderer(components, handleMissingComponent), - [components, handleMissingComponent], + () => + getNodeRenderer( + components ? mergeComponents(defaultComponents, components) : defaultComponents, + missingComponentHandler || noop, + ), + [components, missingComponentHandler], ) + + return ( + + ) +}) + +function PortableTextRenderer({ + listNestingMode, + renderNode, + value, +}: { + listNestingMode: ToolkitListNestMode + renderNode: NodeRenderer + value: B | B[] +}): JSX.Element { + const blocks = Array.isArray(value) ? value : [value] + const nested = nestLists(blocks, listNestingMode) const rendered = nested.map((node, index) => renderNode({node: node, index, isInline: false, renderNode}), ) @@ -70,7 +91,7 @@ const getNodeRenderer = ( components: PortableTextReactComponents, handleMissingComponent: MissingComponentHandler, ): NodeRenderer => { - function renderNode(options: Serializable): ReactNode { + const renderNode = (options: Serializable): ReactNode => { const {node, index, isInline} = options const key = node._key || `node-${index}` @@ -101,16 +122,16 @@ const getNodeRenderer = ( return renderUnknownType(node, index, key, isInline) } - function hasCustomComponentForNode(node: TypedObject): boolean { + const hasCustomComponentForNode = (node: TypedObject): boolean => { return node._type in components.types } /* eslint-disable react/jsx-no-bind */ - function renderListItem( + const renderListItem = ( node: PortableTextListItemBlock, index: number, key: string, - ) { + ) => { const tree = serializeBlock({node, index, isInline: false, renderNode}) const renderer = components.listItem const handler = typeof renderer === 'function' ? renderer : renderer[node.listItem] @@ -139,7 +160,7 @@ const getNodeRenderer = ( ) } - function renderList(node: ReactPortableTextList, index: number, key: string) { + const renderList = (node: ReactPortableTextList, index: number, key: string) => { const children = node.children.map((child, childIndex) => renderNode({ node: child._key ? child : {...child, _key: `li-${index}-${childIndex}`}, @@ -165,7 +186,7 @@ const getNodeRenderer = ( ) } - function renderSpan(node: ToolkitNestedPortableTextSpan, _index: number, key: string) { + const renderSpan = (node: ToolkitNestedPortableTextSpan, _index: number, key: string) => { const {markDef, markType, markKey} = node const Span = components.marks[markType] || components.unknownMark const children = node.children.map((child, childIndex) => @@ -190,7 +211,7 @@ const getNodeRenderer = ( ) } - function renderBlock(node: PortableTextBlock, index: number, key: string, isInline: boolean) { + const renderBlock = (node: PortableTextBlock, index: number, key: string, isInline: boolean) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const {_key, ...props} = serializeBlock({node, index, isInline, renderNode}) const style = props.node.style || 'normal' @@ -208,7 +229,7 @@ const getNodeRenderer = ( return } - function renderText(node: ToolkitTextNode, key: string) { + const renderText = (node: ToolkitTextNode, key: string) => { if (node.text === '\n') { const HardBreak = components.hardBreak return HardBreak ? : '\n' @@ -217,7 +238,7 @@ const getNodeRenderer = ( return node.text } - function renderUnknownType(node: TypedObject, index: number, key: string, isInline: boolean) { + const renderUnknownType = (node: TypedObject, index: number, key: string, isInline: boolean) => { const nodeOptions = { value: node, isInline, @@ -231,7 +252,7 @@ const getNodeRenderer = ( return } - function renderCustomBlock(node: TypedObject, index: number, key: string, isInline: boolean) { + const renderCustomBlock = (node: TypedObject, index: number, key: string, isInline: boolean) => { const nodeOptions = { value: node, isInline, @@ -247,7 +268,7 @@ const getNodeRenderer = ( return renderNode } -function serializeBlock(options: Serializable): SerializedBlock { +const serializeBlock = (options: Serializable): SerializedBlock => { const {node, index, isInline, renderNode} = options const tree = buildMarksTree(node) const children = tree.map((child, i) =>