Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React integration requires dangerouslySetInnerHTML + svg() output is inflexible #3

Open
firxworx opened this issue Jul 6, 2024 · 1 comment

Comments

@firxworx
Copy link

firxworx commented Jul 6, 2024

Beautiful library, it actually works... and then...
The only way to use the SVG that it creates with React is with dangerouslySetInnerHTML! Nooooo! :)

These days one has to be mindful about the potential for supply chain attacks especially with npm packages these days so that makes it hard to use this library as published. I suppose one could add DOMPurify or work with a fork since you published as MIT (thank-you!).

Suggestions --

An option to get an SVG data URL to load into an image tag would be a nice feature request.

QRSvg.ts could be split up as helpers so a React component could import and use them and do that final step of constructing the SVG element.

This would also make it nicely (and safely!) compatible with pretty much any UI framework and vanillajs.

I think this step of the svg() method should be something that downstream consumers of the library should be able to do on their own. This will also enable them to easily add things like <title>, omit a hardcoded width and height for fluid/responsive sizes driven by css, and other tidbits to meet various requirements.

    return `\
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" width="${size}" height="${size}" fill="${fill}">
${this.svgAdditionalContent(this.options.preContent)}
${this.paths.join('\n')}
${this.svgAdditionalContent(this.options.postContent)}
</svg>`;

Right now its not possible because of how QRSvg is implemented as a class.

I suppose you could always publish a React component too since the "guts" are practically already there!

I imagine you created this library for a project you were working on, so thank-you kindly for taking the time to publish and share it to the world.

@avin
Copy link
Owner

avin commented Jul 7, 2024

Hey! You can use this construction:

`data:image/svg+xml;base64,${btoa(qrSvg.svg)}`

Full react component may be like this:

import React, { useMemo } from 'react';
import { QRCode, QRSvg } from 'sexy-qr';

interface Props extends React.HTMLAttributes<HTMLImageElement> {
  payload: string;
  size: number;
  radiusFactor?: number;
}

const Qr = ({ payload, size, radiusFactor = 1, ...props }: Props): JSX.Element => {
  const imgSrc = useMemo(() => {
    const qrCode = new QRCode({
      content: payload,
      ecl: 'M', // 'L' | 'M' | 'Q' | 'H'
    });

    const qrSvg = new QRSvg(qrCode, {
      fill: '#000',
      cornerBlocksAsCircles: false,
      size, // px
      radiusFactor, // 0-1
      cornerBlockRadiusFactor: 2, // 0-3
      roundOuterCorners: true,
      roundInnerCorners: false,
      preContent: `<!-- QR Content: ${payload} -->`,
    });

    return `data:image/svg+xml;base64,${btoa(qrSvg.svg)}`;
  }, [payload, isDarkTheme, size, radiusFactor]);

  return <img {...props} src={imgSrc} alt="QR" />;
};

export default Qr;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants