From b09bfdd01d3c262555d9aa8c4ad2d8f1b6984d01 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Thu, 22 Apr 2021 15:42:23 -0400 Subject: [PATCH] update changelog --- docs/_sidebar.md | 1 + docs/components/qr-code.md | 60 ++++++++++++++++++++ docs/resources/changelog.md | 5 +- package-lock.json | 13 ++++- package.json | 3 +- src/components/qr-code/qr-code.scss | 17 ++++++ src/components/qr-code/qr-code.ts | 86 +++++++++++++++++++++++++++++ src/shoelace.ts | 1 + 8 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 docs/components/qr-code.md create mode 100644 src/components/qr-code/qr-code.scss create mode 100644 src/components/qr-code/qr-code.ts diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 2216ebbe7..6827dd7d8 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -56,6 +56,7 @@ - [Format Date](/components/format-date.md) - [Format Number](/components/format-number.md) - [Include](/components/include.md) + - [QR Code](/components/qr-code.md) - [Relative Time](/components/relative-time.md) - [Resize Observer](/components/resize-observer.md) diff --git a/docs/components/qr-code.md b/docs/components/qr-code.md new file mode 100644 index 000000000..373167037 --- /dev/null +++ b/docs/components/qr-code.md @@ -0,0 +1,60 @@ +# QR Code + +[component-header:sl-qr-code] + +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). + +QR codes are useful for providing small pieces of information to users who can quickly scan them with a smartphone. Most smartphones have built-in QR code scanners, so simply pointing the camera at a QR code will decode it and allow the user to visit a website, dial a phone number, read a message, etc. + +```html preview + +``` + +## Examples + +### Colors + +Use the `fill` and `background` props to modify the QR code's colors. You should always ensure good contrast for optimal compatibility with QR code scanners. + +```html preview + +``` + +### Size + +Use the `size` prop to change the size of the QR code. + +```html preview + +``` + +### Radius + +Create a rounded effect with the `radius` prop. + +```html preview + +``` + +### Error Correction + +QR codes can be rendered with various levels of [error correction](https://www.qrcode.com/en/about/error_correction.html) that can be set using the `error-correction` attribute. This example generates four codes with the same value using different error correction levels. + +```html preview +
+ + + + +
+ + +``` + +[component-metadata:sl-qr-code] diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index 55789086f..82f3281ed 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -6,9 +6,10 @@ Components with the Experimental badge _During the beta period, these restrictions may be relaxed in the event of a mission-critical bug._ 🐛 -## Next +## 2.0.0-beta.39 -- Added the `system` icon library and updated all components to use this instead of the default icon library [#420](https://github.com/shoelace-style/shoelace/issues/420) +- Added experimental `sl-qr-code` component +- Added `system` icon library and updated all components to use this instead of the default icon library [#420](https://github.com/shoelace-style/shoelace/issues/420) - Updated to esbuild 0.8.57 - Updated to lit 2.0.0-rc.1 and lit-html 2.0.0-rc.2 diff --git a/package-lock.json b/package-lock.json index 58372f45a..25e41a049 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "@shoelace-style/animations": "^1.1.0", "color": "^3.1.3", "lit": "^2.0.0-rc.1", - "lit-html": "^2.0.0-rc.2" + "lit-html": "^2.0.0-rc.2", + "qr-creator": "^1.0.0" }, "devDependencies": { "@types/color": "^3.0.1", @@ -3623,6 +3624,11 @@ "once": "^1.3.1" } }, + "node_modules/qr-creator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/qr-creator/-/qr-creator-1.0.0.tgz", + "integrity": "sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ==" + }, "node_modules/qs": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", @@ -8134,6 +8140,11 @@ "once": "^1.3.1" } }, + "qr-creator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/qr-creator/-/qr-creator-1.0.0.tgz", + "integrity": "sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ==" + }, "qs": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", diff --git a/package.json b/package.json index 189cf559a..3dd2c94e3 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,8 @@ "@shoelace-style/animations": "^1.1.0", "color": "^3.1.3", "lit": "^2.0.0-rc.1", - "lit-html": "^2.0.0-rc.2" + "lit-html": "^2.0.0-rc.2", + "qr-creator": "^1.0.0" }, "devDependencies": { "@types/color": "^3.0.1", diff --git a/src/components/qr-code/qr-code.scss b/src/components/qr-code/qr-code.scss new file mode 100644 index 000000000..b2322339b --- /dev/null +++ b/src/components/qr-code/qr-code.scss @@ -0,0 +1,17 @@ +@use '../../styles/component'; + +:host { + display: inline-block; +} + +.qr-code { + position: relative; +} + +canvas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} diff --git a/src/components/qr-code/qr-code.ts b/src/components/qr-code/qr-code.ts new file mode 100644 index 000000000..64b9f552c --- /dev/null +++ b/src/components/qr-code/qr-code.ts @@ -0,0 +1,86 @@ +import { LitElement, html, unsafeCSS } from 'lit'; +import { customElement, property, query } from 'lit/decorators'; +import { styleMap } from 'lit-html/directives/style-map'; +import { watch } from '../../internal/decorators'; +import QrCreator from 'qr-creator'; +import styles from 'sass:./qr-code.scss'; + +/** + * @since 2.0 + * @status experimental + * + * @part base - The component's base wrapper. + */ +@customElement('sl-qr-code') +export default class SlQrCode extends LitElement { + static styles = unsafeCSS(styles); + + @query('canvas') canvas: HTMLElement; + + /** The QR code's value. */ + @property() value = ''; + + /** The label used when screen readers announce the code. If unspecified, the value will be used. */ + @property() label = ''; + + /** The size of the code's overall square 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 = '#000'; + + /** The background color. This can be any valid CSS color or `transparent`, but not a CSS custom property. */ + @property() background = '#fff'; + + /** 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. */ + @property({ attribute: 'error-correction' }) errorCorrection: 'L' | 'M' | 'Q' | 'H' = 'H'; + + firstUpdated() { + this.generate(); + } + + @watch('background') + @watch('errorCorrection') + @watch('fill') + @watch('radius') + @watch('size') + @watch('value') + generate() { + QrCreator.render( + { + text: this.value, + radius: this.radius, + ecLevel: this.errorCorrection, + fill: this.fill, + background: this.background === 'transparent' ? null : 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 + ); + } + + render() { + return html` +
+ +
+ `; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'sl-qr-code': SlQrCode; + } +} diff --git a/src/shoelace.ts b/src/shoelace.ts index 482edb3f3..2c74e7858 100644 --- a/src/shoelace.ts +++ b/src/shoelace.ts @@ -28,6 +28,7 @@ export { default as SlMenuItem } from './components/menu-item/menu-item'; export { default as SlMenuLabel } from './components/menu-label/menu-label'; export { default as SlProgressBar } from './components/progress-bar/progress-bar'; export { default as SlProgressRing } from './components/progress-ring/progress-ring'; +export { default as SlQrCode } from './components/qr-code/qr-code'; export { default as SlRadio } from './components/radio/radio'; export { default as SlRadioGroup } from './components/radio-group/radio-group'; export { default as SlRange } from './components/range/range';