Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ typings/

# automatically generated for any operations where npm modifies
package-lock.json

# Storybook
storybook-static/
16 changes: 16 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {},
};
export default config;
14 changes: 14 additions & 0 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Preview } from '@storybook/react';

const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};

export default preview;
20 changes: 16 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"types": "dist/esm/index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc"
"build": "tsc",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"repository": {
"type": "git",
Expand All @@ -29,11 +31,21 @@
},
"homepage": "https://github.com/gcoro/react-qrcode-logo#readme",
"devDependencies": {
"@storybook/addon-essentials": "^8.6.14",
"@storybook/addon-interactions": "^8.6.14",
"@storybook/addon-links": "^8.6.15",
"@storybook/blocks": "^8.6.14",
"@storybook/react": "^8.6.15",
"@storybook/react-vite": "^8.6.15",
"@storybook/test": "^8.6.15",
"@types/node": "^25.0.9",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"typescript": "^5.4.5",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"react-dom": "^18.0.0",
"storybook": "^8.6.15",
"typescript": "^5.4.5",
"vite": "^7.3.1"
},
"dependencies": {
"qrcode-generator": "^2.0.4"
Expand All @@ -42,4 +54,4 @@
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
}
}
}
218 changes: 218 additions & 0 deletions stories/QRCode.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
import type { Meta, StoryObj } from '@storybook/react';
import { QRCode } from '../lib/index';

const meta: Meta<typeof QRCode> = {
title: 'Components/QRCode',
component: QRCode,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
value: {
control: 'text',
description: 'The value encoded in the QR Code',
},
size: {
control: { type: 'range', min: 100, max: 500, step: 10 },
description: 'The size of the QR Code in pixels',
},
bgColor: {
control: 'color',
description: 'Background color',
},
fgColor: {
control: 'color',
description: 'Foreground color',
},
qrStyle: {
control: 'select',
options: ['squares', 'dots', 'fluid'],
description: 'Style of the QR Code modules',
},
logoImage: {
control: 'text',
description: 'Logo image URL or base64',
},
logoWidth: {
control: { type: 'range', min: 0, max: 200, step: 5 },
description: 'Logo width in pixels',
},
logoHeight: {
control: { type: 'range', min: 0, max: 200, step: 5 },
description: 'Logo height in pixels',
},
logoOpacity: {
control: { type: 'range', min: 0, max: 1, step: 0.1 },
description: 'Logo opacity (0-1)',
},
eyeRadius: {
control: 'object',
description: 'Corner radius for the positioning patterns (eyes). Can be a number, array of numbers, or array of objects with outer/inner properties.',
},
quietZone: {
control: { type: 'range', min: 0, max: 50, step: 5 },
description: 'Size of the quiet zone around the QR Code',
},
removeQrCodeBehindLogo: {
control: 'boolean',
description: 'Remove QR cells behind the logo',
},
enableCORS: {
control: 'boolean',
description: 'Enable CORS for logo image',
},
},
};

export default meta;
type Story = StoryObj<typeof QRCode>;

// Default story with basic configuration
export const Default: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 200,
},
};

// With logo
export const WithLogo: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 250,
logoImage: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/200px-React-icon.svg.png',
logoWidth: 60,
logoHeight: 60,
enableCORS: true,
},
};

// Dots style
export const DotsStyle: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 200,
qrStyle: 'dots',
fgColor: '#8B5CF6',
},
};

// Fluid style
export const FluidStyle: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 200,
qrStyle: 'fluid',
fgColor: '#10B981',
},
};

// Custom colors
export const CustomColors: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 200,
bgColor: '#1F2937',
fgColor: '#F59E0B',
},
};

// Rounded eyes
export const RoundedEyes: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 200,
eyeRadius: 20,
fgColor: '#EF4444',
},
};

// Rounded outer with sharp inner pupils
export const RoundedOuterSharpInner: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 250,
eyeRadius: [
{ outer: [10, 10, 10, 10], inner: [0, 0, 0, 0] },
{ outer: [10, 10, 10, 10], inner: [0, 0, 0, 0] },
{ outer: [10, 10, 10, 10], inner: [0, 0, 0, 0] },
],
fgColor: '#3B82F6',
},
name: 'Rounded Outer, Sharp Inner',
};

// Sharp outer with rounded inner pupils
export const SharpOuterRoundedInner: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 250,
eyeRadius: [
{ outer: [0, 0, 0, 0], inner: [10, 10, 10, 10] },
{ outer: [0, 0, 0, 0], inner: [10, 10, 10, 10] },
{ outer: [0, 0, 0, 0], inner: [10, 10, 10, 10] },
],
fgColor: '#3B82F6',
},
name: 'Sharp Outer, Rounded Inner',
};

// With logo and custom inner/outer radius
export const LogoWithCustomEyeRadius: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 300,
logoImage: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/200px-React-icon.svg.png',
logoWidth: 70,
logoHeight: 70,
enableCORS: true,
eyeRadius: [
{ outer: [12, 12, 12, 12], inner: [8, 8, 8, 8] },
{ outer: [12, 12, 12, 12], inner: [8, 8, 8, 8] },
{ outer: [12, 12, 12, 12], inner: [8, 8, 8, 8] },
],
removeQrCodeBehindLogo: true,
},
};

// Complex example with all features
export const ComplexExample: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 300,
logoImage: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/200px-React-icon.svg.png',
logoWidth: 60,
logoHeight: 60,
logoOpacity: 0.9,
enableCORS: true,
qrStyle: 'fluid',
eyeRadius: [
{ outer: [15, 15, 15, 15], inner: [10, 10, 10, 10] },
{ outer: [15, 15, 15, 15], inner: [10, 10, 10, 10] },
{ outer: [15, 15, 15, 15], inner: [10, 10, 10, 10] },
],
fgColor: '#6366F1',
bgColor: '#F3F4F6',
quietZone: 20,
removeQrCodeBehindLogo: true,
},
};

// Custom eye colors
export const CustomEyeColors: Story = {
args: {
value: 'https://github.com/gcoro/react-qrcode-logo',
size: 250,
eyeColor: [
{ outer: '#FF0000', inner: '#0000FF' },
{ outer: '#00FF00', inner: '#FF00FF' },
{ outer: '#0000FF', inner: '#FFFF00' },
],
eyeRadius: [
{ outer: [5, 5, 5, 5], inner: [5, 5, 5, 5] },
{ outer: [5, 5, 5, 5], inner: [5, 5, 5, 5] },
{ outer: [5, 5, 5, 5], inner: [5, 5, 5, 5] },
],
},
};
67 changes: 67 additions & 0 deletions stories/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Storybook for react-qrcode-logo

This directory contains Storybook stories for developing and testing the QRCode component.

## Running Storybook

From the root directory:

```bash
npm run storybook
```

This will start Storybook on `http://localhost:6006`

## Building Storybook

To build a static version of Storybook:

```bash
npm run build-storybook
```

The output will be in the `storybook-static` directory.

## Available Stories

The `QRCode.stories.tsx` file includes comprehensive stories demonstrating:

- **Default**: Basic QR code
- **WithLogo**: QR code with a logo
- **DotsStyle**: Using the 'dots' qrStyle
- **FluidStyle**: Using the 'fluid' qrStyle
- **CustomColors**: Custom foreground and background colors
- **RoundedEyes**: Rounded corner eyes with eyeRadius
- **DefaultPupils**: Pupils inherit rounding from eyeRadius (default behavior)
- **SharpPupils**: Pupils with sharp corners (squarePupilRadius=0)
- **RoundedPupils**: Pupils with independent rounded corners
- **LogoWithSquarePupils**: Combining logo with custom pupil radius
- **LogoWithSquarePupilsAndZeroRadius**: Logo with sharp pupils
- **ComplexExample**: All features combined
- **CustomEyeColors**: Different colors for each eye

## Controls

Storybook's Controls addon allows you to interactively adjust all props:

- **value**: The data encoded in the QR code
- **size**: QR code size in pixels
- **bgColor/fgColor**: Background and foreground colors
- **qrStyle**: squares, dots, or fluid
- **logoImage**: URL or base64 logo
- **eyeRadius**: Corner radius for eye outer rings
- **squarePupilRadius**: Corner radius for pupils (undefined = inherit from eyeRadius)
- And many more...

## Adding New Stories

To add new stories, edit `QRCode.stories.tsx` and follow the existing pattern:

```typescript
export const YourStory: Story = {
args: {
value: 'Your QR code data',
// ... other props
},
};
```
3 changes: 2 additions & 1 deletion tsconfig.cjs.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"downlevelIteration": true, /* Provide full support for iterables in for..of, spread, and destructuring when targeting ES5 or ES3. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"outDir": "./dist/cjs" /* Redirect output structure to the directory. */
}
},
"exclude": ["playground", "stories", ".storybook"]
}
3 changes: 2 additions & 1 deletion tsconfig.esm.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"module": "ESNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"outDir": "./dist/esm", /* Redirect output structure to the directory. */
"moduleResolution": "node", /* Tells the compiler how to look up and resolve imported modules */
}
},
"exclude": ["playground", "stories", ".storybook"]
}