diegomura / react-pdf

📄 Create PDF files using React
https://react-pdf.org
MIT License
15.02k stars 1.19k forks source link

My use of `<PDFViewer style={PDFStyles.viewer}>` results in error that does not exist when just using `<Document>` #2761

Open guymartinello opened 6 months ago

guymartinello commented 6 months ago

Describe the bug New to most of the below, and wanted to conditionally render a Fluent UI Icon [checkbox].

Using <PDFViewer style={PDFStyles.viewer}> results in error that does not exist when just using <Document>

Error - "Invalid '' string child outside "

To Reproduce Run the code below with <PDFViewer style={PDFStyles.viewer}> the error appears – along with not formatted in rows [I believe caused by the fact that it stops rendering on error]

You can make use of react-pdf REPL to share the snippet

REPL did not provide <PDFViewer> so am providing all code below [apologies]

import React, { Fragment, useEffect, useState } from "react";
import { Image, Font, Document, Page, Text, View, StyleSheet, PDFViewer } from '@react-pdf/renderer';
import type { IPciSelfAssessmentsProps } from './IPciSelfAssessmentsProps';
//https://github.com/microsoft/fluentui/wiki/Using-icons#alternative-cdn-options
import { registerIcons } from '@fluentui/react/lib/Styling';
import { ChevronDownIcon } from '@fluentui/react-icons-mdl2';

registerIcons({
    icons: {
        ChevronDown: <ChevronDownIcon />
    }
});

import { Icon } from '@fluentui/react/lib/Icon';

export const PciSelfAssessments: React.FC<IPciSelfAssessmentsProps> = (props) => {

    const { description, isDarkTheme, environmentMessage, hasTeamsContext, userDisplayName, spfxContext, } = props;
    const [tableData, setTableData] = useState<{ column: string[], data: any[] }>({ column: [], data: [] });
    // const logo = require('../assets/Checkmark.jpg');

    const data = {
        "column": [
            "status",
            "price",
            "email",
            "time"
        ],
        "data": [
            {
                "status": "completed",
                "price": "1",
                "email": "@.com",
                "time": "12:45"
            },
            {
                "status": "not completed",
                "price": "",
                "email": "",
                "time": ""
            }
        ]
    }

    const PDFStyles = StyleSheet.create({
        rowView: {
            display: 'flex', flexDirection: 'row', border: '1px solid #EEE', paddingTop: 8, paddingBottom: 8, textAlign: "center"
        },
        page: {
            flexDirection: 'row',
            backgroundColor: '#E4E4E4',
            color: "black",
        },
        section: {
            margin: 10,
            padding: 10,
            flexGrow: 1,
        },
        viewer: {
            display: 'flex', flexDirection: 'row',
            width: window.innerWidth,
            height: window.innerHeight,
        }
    });

    useEffect(() => {
        if (data !== undefined) setTableData(data);
    }, []);

    //https://stackoverflow.com/users/20434644/yolomama
    return (
        <>
            {tableData.data.length > 0 ? (
                <PDFViewer style={PDFStyles.viewer}>
                    <Document>
                        <Page size={"A4"} style={PDFStyles.page}>
                            <View style={PDFStyles.rowView}>
                                {tableData["column"].map((c: any) => <Text style={{
                                    width: `${100 / tableData["column"].length}%`
                                }}>{c}</Text>)}
                            </View>
                            {tableData["data"].map((rowData: any) => <>
                                <View style={PDFStyles.rowView} >
                                    {tableData["column"].map((c: any) => {

                                        switch (c) {
                                            case "status":
                                                if (rowData[c] === "completed") {
                                                    return [<Text style={{ width: `${100 / tableData["column"].length}%` }}><Icon iconName="CheckboxComposite" /></Text>];
                                                } else {
                                                    return [<Text style={{ width: `${100 / tableData["column"].length}%` }}>{<Icon iconName="Checkbox" />}</Text>];
                                                }
                                                break;
                                            default:
                                                return <Text style={{ width: `${100 / tableData["column"].length}%` }}>{rowData[c]}</Text>;
                                        }
                                    }

                                    )}
                                </View>
                            </>)}
                        </Page >
                    </Document>
                </PDFViewer>
            ) : <></>}
        </>
    );

}

Package.json { "name": "pci-self-assessments", "version": "0.0.1", "private": true, "engines": { "node": ">=16.13.0 <17.0.0 || >=18.17.1 <19.0.0" }, "main": "lib/index.js", "scripts": { "build": "gulp bundle", "clean": "gulp clean", "test": "gulp test", "serve": "fast-serve" }, "dependencies": { "@fluentui/react": "^8.118.4", "@fluentui/react-icons": "^2.0.240", "@fluentui/react-icons-mdl2": "^1.3.66", "@fortawesome/free-solid-svg-icons": "^6.5.2", "@microsoft/sp-component-base": "1.18.2", "@microsoft/sp-core-library": "1.18.2", "@microsoft/sp-lodash-subset": "1.18.2", "@microsoft/sp-office-ui-fabric-core": "1.18.2", "@microsoft/sp-property-pane": "1.18.2", "@microsoft/sp-webpart-base": "1.18.2", "@pnp/core": "^4.0.1", "@pnp/graph": "^4.0.1", "@pnp/logging": "^4.0.1", "@pnp/queryable": "^4.0.1", "@pnp/sp": "^3.6.0", "@pnp/sp-commonjs": "^2.15.0", "@pnp/spfx-controls-react": "3.18.0", "@react-pdf/layout": "3.6.4", "@react-pdf/renderer": "3.1.15", "immer": "^10.1.1", "react": "17.0.1", "react-dom": "17.0.1", "tslib": "2.3.1" }, "overrides": { "@react-pdf/layout": "3.6.4", "@react-pdf/textkit": "4.2.1" }, "devDependencies": { "@microsoft/eslint-config-spfx": "1.18.2", "@microsoft/eslint-plugin-spfx": "1.18.2", "@microsoft/rush-stack-compiler-4.7": "0.1.0", "@microsoft/sp-build-web": "1.18.2", "@microsoft/sp-module-interfaces": "1.18.2", "@rushstack/eslint-config": "2.5.1", "@types/react": "17.0.45", "@types/react-dom": "17.0.17", "@types/webpack-env": "~1.15.2", "ajv": "^6.12.5", "eslint": "8.7.0", "eslint-plugin-react-hooks": "4.3.0", "gulp": "^4.0.2", "spfx-fast-serve-helpers": "~1.18.0", "typescript": "4.7.4" } }

Gulpfile.js

"use strict";

const build = require("@microsoft/sp-build-web");

build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);

var getTasks = build.rig.getTasks;
build.rig.getTasks = function () {
    var result = getTasks.call(build.rig);

    result.set("serve", result.get("serve-deprecated"));

    return result;
};
build.tslintCmd.enabled = false;
/* fast-serve */
const { addFastServe } = require("spfx-fast-serve-helpers");
addFastServe(build);
/* end of fast-serve */

build.initialize(require('gulp'));

build.configureWebpack.mergeConfig({
    additionalConfiguration: (wpcfg) => {
        // if dev build, mod config for profiling react
        if (wpcfg.mode === "development") {
            // add alias for the react-dom profiler
            wpcfg.resolve.alias = {
                "react-dom$": "react-dom/profiling",
            };

            // remove externalization of react & react-dom
            wpcfg.externals = wpcfg.externals.filter((external) => {
                return external !== "react" && external !== "react-dom";
            });
        }

        return wpcfg;
    },
});

build.configureWebpack.mergeConfig({
    additionalConfiguration: (generatedConfig) => {
###         **generatedConfig.resolve.extensions = [".mjs", ".js", ".mts", ".ts", ".jsx", ".tsx", ".json"],**

            console.log('<webpack.config type="object">');
        console.log(generatedConfig);
        console.log('</webpack.config>');

        console.log('<webpack.config type="string">');
        console.log(JSON.stringify(generatedConfig));
        console.log('</webpack.config>');

        return generatedConfig;
    }
});

Expected behavior A clear and concise description of what you expected to happen. Expected to render per first print screen , but within the control

Screenshots Rendered without PDFViewer

image

Rendered using PDFViewer

image
guymartinello commented 6 months ago

minor update on this, I was able to get the checkmark to render with the code below - but it still is not displaying in a table format as it does without <PDFViewer>

return (
        <>
            {tableData.data.length > 0 ? (
                <PDFViewer style={PDFStyles.viewer}>
                    <Document>
                        <Page size={"A4"} style={PDFStyles.page}>
                            <View style={PDFStyles.rowView}>
                                {tableData["column"].map((c: any) => <Text style={{
                                    width: `${100 / tableData["column"].length}%`
                                }}>{c}</Text>)}
                            </View>
                            {tableData["data"].map((rowData: any) => <>
                                <View style={PDFStyles.rowView} >
                                    {tableData["column"].map((c: any) => {

                                        switch (c) {
                                            case "status":
                                                if (rowData[c] === "completed") {
                                                    return <Image style={PDFStyles.image} source={require("../assets/Checkmark.jpg")} />;
                                                } else {
                                                    return <Image style={PDFStyles.image} source={require("../assets/Checkmark.jpg")} />;
                                                }
                                                break;
                                            default:
                                                return <Text style={{ width: `${100 / tableData["column"].length}%` }}>{rowData[c]}</Text>;
                                        }
                                        /*
                                        switch (c) {
                                            case "status":
                                                if (rowData[c] === "completed") {
                                                    return [<Text style={{ width: `${100 / tableData["column"].length}%` }}><Icon iconName="CheckboxComposite" /></Text>];
                                                } else {
                                                    return [<Text style={{ width: `${100 / tableData["column"].length}%` }}>{<Icon iconName="Checkbox" />}</Text>];
                                                }
                                                break;
                                            default:
                                                return <Text style={{ width: `${100 / tableData["column"].length}%` }}>{rowData[c]}</Text>;
                                        }
                                        */
                                    }

                                    )}
                                </View>
                            </>)}
                        </Page >
                    </Document>
                </PDFViewer>
            ) : <></>}
        </>
    );

}
image
guymartinello commented 6 months ago

I think that i fixed it [bar some formatting issues] by changing page style from row to column

page: {
            flexDirection: 'column',
            backgroundColor: '#E4E4E4',
            color: "black",
        },