Skip to content

feat: Added QR code component with encoding and rendering capabilities - #2242

Merged
rkaraivanov merged 13 commits into
masterfrom
rkaraivanov/qr-code
Aug 4, 2026
Merged

feat: Added QR code component with encoding and rendering capabilities#2242
rkaraivanov merged 13 commits into
masterfrom
rkaraivanov/qr-code

Conversation

@rkaraivanov

Copy link
Copy Markdown
Member

Description

Added a new component able to encode and render data as a QR code SVG

Type of Change

  • New feature (non-breaking change that adds functionality)

Checklist

  • My code follows the project's coding standards
  • I have tested my changes locally

Some of the key changes include:
- Added new properties to the QR code component for logo source, size, and margin.
- Updated the QR code generation logic to account for the logo area and error correction level.
- Refactored the corner rendering logic to ensure the finder patterns are not obscured by the logo.
- Added new tests to cover the logo functionality and ensure the QR code is still scannable with the logo present.
Copilot AI review requested due to automatic review settings August 4, 2026 09:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new igc-qr-code web component that can encode input data into a QR matrix and render it as an SVG, with customization options (error correction, sizing, module/corner styles, optional centered logo). It also adds Storybook coverage and a fairly comprehensive unit test suite for both the component and the underlying QR encoding/model logic.

Changes:

  • Added IgcQrCodeComponent with SVG rendering, styling knobs, and optional logo masking.
  • Implemented a QR encoder/model pipeline (encoding, ECC, masking, matrix generation) with unit tests.
  • Added Storybook stories and exported the new component from the package entrypoint.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
stories/qr-code.stories.ts Adds Storybook documentation and visual test cases for QR code variants (styles, colors, sizes, logos).
src/index.ts Exports IgcQrCodeComponent from the package entrypoint.
src/components/qr-code/types.ts Introduces public type unions for QR styles, error correction level, and encoding mode.
src/components/qr-code/renderer/constants.ts Defines renderer constants (CSS var-based colors) and safe-area defaults for logo sizing.
src/components/qr-code/renderer/helpers.ts Implements SVG path generation for modules and finder patterns plus helper geometry.
src/components/qr-code/renderer/dots.ts Renders data modules as a single SVG path from the boolean matrix.
src/components/qr-code/renderer/corner.ts Renders finder patterns separately to allow style customization.
src/components/qr-code/renderer/image.ts Renders the logo <image> and optional mask to preserve scannability.
src/components/qr-code/qr-code.ts Implements the Lit component, properties/attributes, SVG output, and logo handling.
src/components/qr-code/qr-code.spec.ts Adds component-level tests including a11y checks, rendering behavior, and logo validation/structure.
src/components/qr-code/model/qr-model.spec.ts Adds model-level tests for encoding mode detection, ECC behavior, masking, and matrix structure.
src/components/qr-code/model/matrix.ts Implements matrix construction (finder/timing/alignment/data placement + format/version info + masking).
src/components/qr-code/model/mask.ts Implements mask application and penalty scoring to select the best mask pattern.
src/components/qr-code/model/error-correction.ts Implements Reed–Solomon ECC and QR block interleaving with the EC blocks table.
src/components/qr-code/model/encode.ts Implements data encoding to codewords, including version selection and padding.
src/components/common/util.ts Adds documentation to nanoid() used for stable SVG mask IDs.

Comment thread src/components/qr-code/qr-code.ts
Comment thread src/components/qr-code/qr-code.ts Outdated
Comment thread src/components/qr-code/model/error-correction.ts Outdated
Comment thread src/components/qr-code/model/encode.ts
Copilot AI review requested due to automatic review settings August 4, 2026 12:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Suppressed comments (4)

src/components/qr-code/qr-code.ts:119

  • The logoSize documentation describes it as a ratio of the QR code size (and implies 1 would fill the whole code), but the implementation treats it as a multiplier of MAX_SAFE_AREA (targetArea = logoSize * MAX_SAFE_AREA). This mismatch will confuse consumers and makes the default description (“40% of the QR code size”) inaccurate.
  /**
   * The size of the logo as a ratio of the QR code size. This determines how large the logo will appear within the QR code.
   * The value should be a number between 0 and 1, where 0 means no logo and 1 means the logo will take up the entire QR code (which is not recommended).
   * The default value is 0.4, meaning the logo will take up 40% of the QR code size.
   *

src/components/qr-code/renderer/constants.ts:26

  • The comment for DEFAULT_SIZE_RATIO states it represents “40% of the QR code area”, but DEFAULT_SIZE_RATIO is just the default logoSize factor and is later converted/capped by safe-area logic. As written, the comment is misleading.
/**
 * Default size ratio for the logo relative to the QR code. This means that by default, the logo will occupy 40% of the QR code area.
 * This is a conservative default that allows for a reasonably sized logo while maintaining good scannability.
 */

src/components/qr-code/qr-code.ts:26

  • The component JSDoc starts with an empty summary line (* on its own), which is currently propagating into generated docs/Storybook as a leading newline. This is just formatting noise in the public docs.

This issue also appears on line 115 of the same file.

/**
 *
 * Generates a QR code based on the provided value and options.
 * The component renders an SVG representation of the QR code, which can be customized using various properties.
 *

src/components/qr-code/renderer/constants.ts:4

  • The QR code uses --igc-qr-* for the main colors, but the corner colors are exposed as --qr-corner-* (no --igc- prefix). Since these CSS custom properties are part of the public styling API, the inconsistent naming is likely to be a long-term footgun for consumers and makes them harder to discover alongside other --igc-* variables used across the codebase (e.g. var(--igc-chat-height) in src/components/chat/themes/chat.base.scss).

This issue also appears on line 23 of the same file.

const DOT_COLOR = 'var(--igc-qr-dark, #000)';
const DOT_BACKGROUND = 'var(--igc-qr-background, #fff)';
const CORNER_SQUARE_COLOR = 'var(--qr-corner-square-fill, #000)';
const CORNER_DOT_COLOR = 'var(--qr-corner-dot-fill, #000)';

* feat(qr-code): adopt igniteui-theming for component theming

Depends on IgniteUI/igniteui-theming#593

* deps(theming): bump to latest version
Copilot AI review requested due to automatic review settings August 4, 2026 13:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 32 changed files in this pull request and generated no new comments.

Suppressed comments (4)

src/components/qr-code/qr-code.ts:121

  • The logoSize docs describe it as a ratio of the full QR code size (including claiming 1 = the entire QR code), but the implementation uses logoSize as a multiplier of MAX_SAFE_AREA (i.e. a ratio of the maximum safe area). The docs should match the actual behavior so consumers can predict sizing.
   * The size of the logo as a ratio of the QR code size. This determines how large the logo will appear within the QR code.
   * The value should be a number between 0 and 1, where 0 means no logo and 1 means the logo will take up the entire QR code (which is not recommended).
   * The default value is 0.4, meaning the logo will take up 40% of the QR code size.

src/components/qr-code/renderer/constants.ts:21

  • DEFAULT_SIZE_RATIO is documented as "40% of the QR code area", but logoSize is multiplied by MAX_SAFE_AREA, so the default corresponds to 40% of the maximum safe area (not 40% of the full QR code area).
 * Default size ratio for the logo relative to the QR code. This means that by default, the logo will occupy 40% of the QR code area.
 * This is a conservative default that allows for a reasonably sized logo while maintaining good scannability.
 */

src/components/qr-code/qr-code.ts:139

  • dotStyle is documented as applying to the data modules only, but it is also passed as the finder-pattern corner dot style (see renderQrFinders call). Either document that it affects the corner dots too, or introduce a separate property for corner-dot styling.
   * The style of the data modules (dots) in the QR code. This can be 'square', 'circle', or 'rounded'.

src/components/qr-code/qr-code.ts:36

  • The component exposes several CSS custom properties (e.g. --ig-qr-code-background, --ig-qr-code-dark-color) that are used in the story/tests, but they are not documented in the component JSDoc. This means the generated API docs will miss these theming hooks.
 * @csspart background - The background rect of the QR code.
 * @csspart dots - The data modules (dots) of the QR code.
 * @csspart corner-square - The outer corner (finder-pattern) squares of the QR code.
 * @csspart corner-dot - The inner corner (finder-pattern) dots of the QR code.
 */

Copilot AI review requested due to automatic review settings August 4, 2026 15:01
@rkaraivanov
rkaraivanov marked this pull request as ready for review August 4, 2026 15:02
@simeonoff
simeonoff self-requested a review August 4, 2026 15:06
@simeonoff simeonoff self-assigned this Aug 4, 2026
@rkaraivanov
rkaraivanov merged commit 9f4e647 into master Aug 4, 2026
8 checks passed
@rkaraivanov
rkaraivanov deleted the rkaraivanov/qr-code branch August 4, 2026 15:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 33 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/components/qr-code/model/matrix.ts:373

  • Mask pattern selection is computed before format information bits (and the fixed dark module at (size-8,8)) are written into the candidate matrices. QR mask penalty evaluation is defined over the final symbol, so excluding format info can pick a different “best” mask than intended and reduce scan reliability.
  // Select best mask
  const bestMask = selectBestMask(matrix, functionModules);

  // Apply the best mask to the data modules
  const maskedMatrix = applyMask(matrix, functionModules, bestMask);

src/components/qr-code/qr-code.ts:252

  • errorLevel is initialized to 'M', so _getErrorLevelAndArea() always treats it as user-specified and never runs the auto-pick branch. This contradicts the documented behavior (“when error-level is not explicitly set… chosen automatically”) and prevents auto-raising the EC level to accommodate a logo.
  private _getErrorLevelAndArea(hasLogo: boolean) {
    const userErrorLevel = this.errorLevel;
    const size = this.logoSize;
    const sizeRatio = hasLogo ? clamp(size ?? DEFAULT_SIZE_RATIO, 0, 1) : 0;
    const targetArea = sizeRatio * MAX_SAFE_AREA;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants