diff --git a/.changeset/mean-pots-allow.md b/.changeset/mean-pots-allow.md
new file mode 100644
index 000000000..027f21b80
--- /dev/null
+++ b/.changeset/mean-pots-allow.md
@@ -0,0 +1,5 @@
+---
+'@react-pdf/renderer': patch
+---
+
+fix: skip empty text instance creation in jsx conditions
diff --git a/packages/renderer/src/renderer.js b/packages/renderer/src/renderer.js
index ffb2973a3..5a69d3220 100644
--- a/packages/renderer/src/renderer.js
+++ b/packages/renderer/src/renderer.js
@@ -11,6 +11,23 @@ import propsEqual from './utils/propsEqual';
const emptyObject = {};
+const appendChild = (parentInstance, child) => {
+ const isParentText = parentInstance.type === 'TEXT';
+ const isChildTextInstance = child.type === 'TEXT_INSTANCE';
+ const isOrphanTextInstance = isChildTextInstance && !isParentText;
+
+ // Ignore orphan text instances.
+ // Caused by cases such as <>{name && {name}}>
+ if (isOrphanTextInstance) {
+ console.warn(
+ `Invalid '${child.value}' string child outside component`,
+ );
+ return;
+ }
+
+ parentInstance.children.push(child);
+};
+
const createRenderer = ({ onChange = () => {} }) => {
return ReactFiberReconciler({
schedulePassiveEffects,
@@ -23,9 +40,7 @@ const createRenderer = ({ onChange = () => {} }) => {
warnsIfNotActing: false,
- appendInitialChild(parentInstance, child) {
- parentInstance.children.push(child);
- },
+ appendInitialChild: appendChild,
createInstance(type, { style, children, ...props }) {
return {
@@ -83,15 +98,13 @@ const createRenderer = ({ onChange = () => {} }) => {
useSyncScheduling: true,
- appendChild(parentInstance, child) {
- parentInstance.children.push(child);
- },
+ appendChild,
appendChildToContainer(parentInstance, child) {
if (parentInstance.type === 'ROOT') {
parentInstance.document = child;
} else {
- parentInstance.children.push(child);
+ appendChild(parentInstance, child);
}
},
diff --git a/packages/renderer/tests/orphanTexts.test.js b/packages/renderer/tests/orphanTexts.test.js
new file mode 100644
index 000000000..7969006ca
--- /dev/null
+++ b/packages/renderer/tests/orphanTexts.test.js
@@ -0,0 +1,48 @@
+/* eslint-disable react/jsx-curly-brace-presence */
+import React from 'react';
+import { Text, Document, Page } from '@react-pdf/primitives';
+import renderToImage from './renderComponent';
+
+const emptyString = '';
+
+const mount = async children => {
+ const image = await renderToImage(
+
+ {children}
+ ,
+ );
+
+ return image;
+};
+
+describe('renderer', () => {
+ test('empty string', async () => {
+ const image = await mount(<>{emptyString && {emptyString}}>);
+
+ expect(image).toMatchImageSnapshot();
+ });
+
+ test('string', async () => {
+ const image = await mount(<>{'text' || text}>);
+
+ expect(image).toMatchImageSnapshot();
+ });
+
+ test('boolean', async () => {
+ const image = await mount(<>{true || text}>);
+
+ expect(image).toMatchImageSnapshot();
+ });
+
+ test('zero', async () => {
+ const image = await mount(<>{0 && text}>);
+
+ expect(image).toMatchImageSnapshot();
+ });
+
+ test('numbers', async () => {
+ const image = await mount(<>{10 || text}>);
+
+ expect(image).toMatchImageSnapshot();
+ });
+});
diff --git a/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-boolean-1-snap.png b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-boolean-1-snap.png
new file mode 100644
index 000000000..d3d4c83d6
Binary files /dev/null and b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-boolean-1-snap.png differ
diff --git a/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-empty-string-1-snap.png b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-empty-string-1-snap.png
new file mode 100644
index 000000000..d3d4c83d6
Binary files /dev/null and b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-empty-string-1-snap.png differ
diff --git a/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-numbers-1-snap.png b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-numbers-1-snap.png
new file mode 100644
index 000000000..d3d4c83d6
Binary files /dev/null and b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-numbers-1-snap.png differ
diff --git a/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-string-1-snap.png b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-string-1-snap.png
new file mode 100644
index 000000000..d3d4c83d6
Binary files /dev/null and b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-string-1-snap.png differ
diff --git a/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-zero-1-snap.png b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-zero-1-snap.png
new file mode 100644
index 000000000..d3d4c83d6
Binary files /dev/null and b/packages/renderer/tests/snapshots/orphan-texts-test-js-renderer-zero-1-snap.png differ