2024-09-11 10:25:42 -04:00
import { customElement , property , query , state } from 'lit/decorators.js' ;
2024-04-17 11:20:27 -04:00
import { html } from 'lit' ;
import { watch } from '../../internal/watch.js' ;
import componentStyles from '../../styles/component.styles.js' ;
import styles from './qr-code.styles.js' ;
import WebAwesomeElement from '../../internal/webawesome-element.js' ;
2024-09-11 10:25:42 -04:00
import type { CSSResultGroup , PropertyValues } from 'lit' ;
import type _QrCreator from 'qr-creator' ;
let QrCreator : _QrCreator.default ;
2023-08-11 10:09:44 -07:00
2024-04-17 11:20:27 -04:00
/ * *
* @summary Generates a [ QR code ] ( https : //www.qrcode.com/) and renders it using the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API).
2024-06-20 11:26:24 -04:00
* @documentation https : //backers.webawesome.com/docs/components/qr-code
2024-04-17 11:20:27 -04:00
* @status stable
* @since 2.0
*
* @csspart base - The component ' s base wrapper .
* /
@customElement ( 'wa-qr-code' )
export default class WaQrCode extends WebAwesomeElement {
static styles : CSSResultGroup = [ componentStyles , styles ] ;
2023-08-11 10:09:44 -07:00
2024-04-17 11:20:27 -04:00
@query ( 'canvas' ) canvas : HTMLElement ;
/** The QR code's value. */
@property ( ) value = '' ;
/** The label for assistive devices to announce. If unspecified, the value will be used instead. */
@property ( ) label = '' ;
/** The size of the QR code, in pixels. */
@property ( { type : Number } ) size = 128 ;
/** The fill color. This can be any valid CSS color, but not a CSS custom property. */
@property ( ) fill = 'black' ;
/** The background color. This can be any valid CSS color or `transparent`. It cannot be a CSS custom property. */
@property ( ) background = 'white' ;
/** The edge radius of each module. Must be between 0 and 0.5. */
@property ( { type : Number } ) radius = 0 ;
/** The level of error correction to use. [Learn more](https://www.qrcode.com/en/about/error_correction.html) */
@property ( { attribute : 'error-correction' } ) errorCorrection : 'L' | 'M' | 'Q' | 'H' = 'H' ;
2024-09-11 10:25:42 -04:00
/ * *
* Whether or not the qr - code generated .
* /
// @ts-expect-error Don't know why it marks it as unused.
@state ( ) private generated = false ;
firstUpdated ( changedProperties : PropertyValues < this > ) {
super . firstUpdated ( changedProperties ) ;
if ( this . hasUpdated ) {
this . generate ( ) ;
}
2024-04-17 11:20:27 -04:00
}
@watch ( [ 'background' , 'errorCorrection' , 'fill' , 'radius' , 'size' , 'value' ] )
generate() {
2024-09-11 10:25:42 -04:00
this . style . setProperty ( '--size' , ` ${ this . size } px ` ) ;
2024-04-17 11:20:27 -04:00
if ( ! this . hasUpdated ) {
return ;
}
2024-09-11 10:25:42 -04:00
// We lazy load because the QR generator will cause the server to crash, but we want to reduce layout shift.
if ( ! QrCreator ) {
import ( 'qr-creator' ) . then ( mod = > {
QrCreator = mod . default ;
this . generate ( ) ;
} ) ;
return ;
}
( QrCreator as unknown as typeof _QrCreator . default ) . render (
2024-04-17 11:20:27 -04:00
{
text : this.value ,
radius : this.radius ,
ecLevel : this.errorCorrection ,
fill : this.fill ,
background : this.background ,
// We draw the canvas larger and scale its container down to avoid blurring on high-density displays
size : this.size * 2
} ,
this . canvas
) ;
2024-09-11 10:25:42 -04:00
this . generated = true ;
2024-04-17 11:20:27 -04:00
}
render() {
return html `
< canvas
part = "base"
class = "qr-code"
role = "img"
aria - label = $ { this . label ? . length > 0 ? this . label : this.value }
> < / canvas >
` ;
}
}
2023-08-11 10:09:44 -07:00
declare global {
interface HTMLElementTagNameMap {
2023-09-08 13:45:49 -04:00
'wa-qr-code' : WaQrCode ;
2023-08-11 10:09:44 -07:00
}
}