jaci-ui 0.9.1 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +17 -12
- package/dist/components/button/button.cjs +9 -3
- package/dist/components/button/button.cjs.map +1 -1
- package/dist/components/button/button.js +9 -3
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/qr-code/qr-code.cjs +86 -41
- package/dist/components/qr-code/qr-code.cjs.map +1 -1
- package/dist/components/qr-code/qr-code.d.cts +4 -1
- package/dist/components/qr-code/qr-code.d.ts +4 -1
- package/dist/components/qr-code/qr-code.js +87 -42
- package/dist/components/qr-code/qr-code.js.map +1 -1
- package/dist/styles.css +6 -6
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 894b4e8: Update Storybook and compatible workspace tooling dependencies to their latest patch releases.
|
|
8
|
+
- 10446a3: Fix `Button.render` with native and framework link elements, including Next.js client boundaries.
|
|
9
|
+
- cdcfb85: Improve QRCode finder contrast in dark themes and add native SVG download support.
|
|
10
|
+
- 77a1b9f: Improve QRCode's native SVG download link accessibility and preserve the QR code's image semantics.
|
|
11
|
+
|
|
3
12
|
## 0.9.1
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -84,10 +84,10 @@ import { AspectRatio, Code, Figure, Image, Kbd, Quote, Stat, StatGroup } from "j
|
|
|
84
84
|
</StatGroup.Root>;
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
###
|
|
87
|
+
### Media and visual utilities
|
|
88
88
|
|
|
89
|
-
`Carousel`
|
|
90
|
-
|
|
89
|
+
`Carousel` provides accessible slides with keyboard navigation, indicators, swipe support and
|
|
90
|
+
optional autoplay. Always provide an `aria-label` on the root and alternative text for images:
|
|
91
91
|
|
|
92
92
|
```tsx
|
|
93
93
|
<Carousel.Root aria-label="Featured projects" loop>
|
|
@@ -108,8 +108,8 @@ opcional. Sempre forneça um `aria-label` no root e texto alternativo nas imagen
|
|
|
108
108
|
</Carousel.Root>
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
`QRCode`
|
|
112
|
-
|
|
111
|
+
`QRCode` generates SVG on the server and client, with circular modules and rounded square eyes.
|
|
112
|
+
The application can control the value directly:
|
|
113
113
|
|
|
114
114
|
```tsx
|
|
115
115
|
<QRCode
|
|
@@ -117,10 +117,15 @@ arredondados. O valor pode ser controlado diretamente pela aplicação:
|
|
|
117
117
|
size={240}
|
|
118
118
|
errorCorrectionLevel="Q"
|
|
119
119
|
label="Jaci UI website"
|
|
120
|
+
download="jaci-ui-qr.svg"
|
|
121
|
+
downloadLabel="Download Jaci UI QR code"
|
|
120
122
|
/>
|
|
121
123
|
```
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
When `download` is provided, the SVG exposes a native link for downloading the code without
|
|
126
|
+
using browser APIs during SSR.
|
|
127
|
+
|
|
128
|
+
For downloads, `DownloadTrigger` is a regular HTML link: it does not fetch or create a `Blob`:
|
|
124
129
|
|
|
125
130
|
```tsx
|
|
126
131
|
<DownloadTrigger href="/files/report.pdf" download="report.pdf">
|
|
@@ -128,19 +133,19 @@ Para downloads, `DownloadTrigger` é um link HTML comum e não faz fetch nem cri
|
|
|
128
133
|
</DownloadTrigger>
|
|
129
134
|
```
|
|
130
135
|
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
For cross-origin URLs, the filename and the download authorization remain subject to browser
|
|
137
|
+
rules and server headers.
|
|
133
138
|
|
|
134
|
-
Use `Separator`
|
|
135
|
-
|
|
139
|
+
Use `Separator` for a semantic or decorative line between sections, and `Spacer` when only
|
|
140
|
+
space—not a line—is needed:
|
|
136
141
|
|
|
137
142
|
```tsx
|
|
138
143
|
<Separator orientation="horizontal" />
|
|
139
144
|
<Spacer axis="vertical" size="lg" />
|
|
140
145
|
```
|
|
141
146
|
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
These components support SSR and React 18/19. Interactive modules declare their client boundary
|
|
148
|
+
where required and do not access browser APIs during import or server rendering.
|
|
144
149
|
|
|
145
150
|
`AspectRatio` fills the available inline size of its parent. In shrink-to-fit or flex
|
|
146
151
|
layouts, give the parent an explicit `width`/`max-width` so the ratio has a measurable
|
|
@@ -16,7 +16,7 @@ function content(children, loading, startIcon, endIcon) {
|
|
|
16
16
|
!loading ? endIcon : void 0
|
|
17
17
|
] });
|
|
18
18
|
}
|
|
19
|
-
const Button = (0, react.forwardRef)(function Button({ children, className, variant = "outline", size = "md", fullWidth = false, loading = false, startIcon, endIcon, disabled, render, type = "button", ...props }, ref) {
|
|
19
|
+
const Button = (0, react.forwardRef)(function Button({ children, className, variant = "outline", size = "md", fullWidth = false, loading = false, startIcon, endIcon, disabled, onClick: buttonOnClick, render, type = "button", ...props }, ref) {
|
|
20
20
|
const buttonClassName = require_cx.cx(require_button.button({
|
|
21
21
|
variant,
|
|
22
22
|
size,
|
|
@@ -24,7 +24,12 @@ const Button = (0, react.forwardRef)(function Button({ children, className, vari
|
|
|
24
24
|
}), className);
|
|
25
25
|
const childrenWithIcons = content(children, loading, startIcon, endIcon);
|
|
26
26
|
if (render) {
|
|
27
|
-
const renderedProps = render.props;
|
|
27
|
+
const renderedProps = render.props ?? {};
|
|
28
|
+
const renderedOnClick = renderedProps.onClick;
|
|
29
|
+
const handleRenderedClick = disabled || loading ? (event) => event.preventDefault() : (event) => {
|
|
30
|
+
renderedOnClick?.(event);
|
|
31
|
+
if (!event.defaultPrevented) buttonOnClick?.(event);
|
|
32
|
+
};
|
|
28
33
|
return (0, react.cloneElement)(render, {
|
|
29
34
|
...props,
|
|
30
35
|
"aria-busy": loading || void 0,
|
|
@@ -33,7 +38,7 @@ const Button = (0, react.forwardRef)(function Button({ children, className, vari
|
|
|
33
38
|
"data-jaci-component": "button",
|
|
34
39
|
"data-slot": "button",
|
|
35
40
|
children: childrenWithIcons,
|
|
36
|
-
onClick:
|
|
41
|
+
onClick: handleRenderedClick
|
|
37
42
|
});
|
|
38
43
|
}
|
|
39
44
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -43,6 +48,7 @@ const Button = (0, react.forwardRef)(function Button({ children, className, vari
|
|
|
43
48
|
"data-jaci-component": "button",
|
|
44
49
|
"data-slot": "button",
|
|
45
50
|
disabled: disabled || loading,
|
|
51
|
+
onClick: buttonOnClick,
|
|
46
52
|
ref,
|
|
47
53
|
type,
|
|
48
54
|
children: childrenWithIcons
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.cjs","names":["Spinner","cx","button"],"sources":["../../../src/components/button/button.tsx"],"sourcesContent":["\"use client\";\n\nimport { cloneElement, forwardRef } from \"react\";\nimport type {
|
|
1
|
+
{"version":3,"file":"button.cjs","names":["Spinner","cx","button"],"sources":["../../../src/components/button/button.tsx"],"sourcesContent":["\"use client\";\n\nimport { cloneElement, forwardRef } from \"react\";\nimport type {\n ComponentPropsWithoutRef,\n MouseEvent,\n MouseEventHandler,\n ReactElement,\n ReactNode,\n} from \"react\";\n\nimport { cx } from \"../../styled-system/css\";\nimport { button } from \"../../styled-system/recipes\";\nimport { Spinner } from \"../layout\";\n\ntype RenderableButtonProps = Record<string, unknown> & {\n children?: ReactNode | undefined;\n className?: string | undefined;\n onClick?: MouseEventHandler<HTMLElement> | undefined;\n};\n\nexport interface ButtonProps\n extends Omit<ComponentPropsWithoutRef<\"button\">, \"color\" | \"children\"> {\n children?: ReactNode;\n variant?: \"outline\" | \"solid\" | \"ghost\" | \"danger\";\n size?: \"sm\" | \"md\" | \"lg\";\n fullWidth?: boolean;\n loading?: boolean;\n startIcon?: ReactNode;\n endIcon?: ReactNode;\n render?: ReactElement<RenderableButtonProps>;\n}\n\nfunction content(children: ReactNode, loading: boolean, startIcon: ReactNode, endIcon: ReactNode) {\n return (\n <>\n {loading ? <Spinner aria-hidden=\"true\" label=\"\" size=\"sm\" /> : startIcon}\n {children}\n {!loading ? endIcon : undefined}\n </>\n );\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n {\n children,\n className,\n variant = \"outline\",\n size = \"md\",\n fullWidth = false,\n loading = false,\n startIcon,\n endIcon,\n disabled,\n onClick: buttonOnClick,\n render,\n type = \"button\",\n ...props\n },\n ref,\n) {\n const buttonClassName = cx(button({ variant, size, fullWidth }), className);\n const childrenWithIcons = content(children, loading, startIcon, endIcon);\n\n if (render) {\n // Some framework adapters (notably React Server Component boundaries) can\n // provide a React element whose props are unavailable until cloning. Keep\n // the render path tolerant of that representation.\n const renderedProps = render.props ?? {};\n const renderedOnClick = renderedProps.onClick as MouseEventHandler<HTMLElement> | undefined;\n const handleRenderedClick: MouseEventHandler<HTMLElement> | undefined =\n disabled || loading\n ? (event) => event.preventDefault()\n : (event) => {\n renderedOnClick?.(event);\n if (!event.defaultPrevented) {\n buttonOnClick?.(event as unknown as MouseEvent<HTMLButtonElement>);\n }\n };\n\n return cloneElement(render, {\n ...props,\n \"aria-busy\": loading || undefined,\n \"aria-disabled\": disabled || loading || undefined,\n className: cx(buttonClassName, renderedProps.className),\n \"data-jaci-component\": \"button\",\n \"data-slot\": \"button\",\n children: childrenWithIcons,\n onClick: handleRenderedClick,\n });\n }\n\n return (\n <button\n {...props}\n aria-busy={loading || undefined}\n className={buttonClassName}\n data-jaci-component=\"button\"\n data-slot=\"button\"\n disabled={disabled || loading}\n onClick={buttonOnClick}\n ref={ref}\n type={type}\n >\n {childrenWithIcons}\n </button>\n );\n});\n"],"mappings":";;;;;;;AAiCA,SAAS,QAAQ,UAAqB,SAAkB,WAAsB,SAAoB;CAChG,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;EACG,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAACA,cAAAA,SAAD;GAAS,eAAY;GAAO,OAAM;GAAG,MAAK;EAAM,CAAA,IAAI;EAC9D;EACA,CAAC,UAAU,UAAU,KAAA;CACtB,EAAA,CAAA;AAEN;AAEA,MAAa,UAAA,GAAA,MAAA,WAAA,CAAoD,SAAS,OACxE,EACE,UACA,WACA,UAAU,WACV,OAAO,MACP,YAAY,OACZ,UAAU,OACV,WACA,SACA,UACA,SAAS,eACT,QACA,OAAO,UACP,GAAG,SAEL,KACA;CACA,MAAM,kBAAkBC,WAAAA,GAAGC,eAAAA,OAAO;EAAE;EAAS;EAAM;CAAU,CAAC,GAAG,SAAS;CAC1E,MAAM,oBAAoB,QAAQ,UAAU,SAAS,WAAW,OAAO;CAEvE,IAAI,QAAQ;EAIV,MAAM,gBAAgB,OAAO,SAAS,CAAC;EACvC,MAAM,kBAAkB,cAAc;EACtC,MAAM,sBACJ,YAAY,WACP,UAAU,MAAM,eAAe,KAC/B,UAAU;GACT,kBAAkB,KAAK;GACvB,IAAI,CAAC,MAAM,kBACT,gBAAgB,KAAiD;EAErE;EAEN,QAAA,GAAA,MAAA,aAAA,CAAoB,QAAQ;GAC1B,GAAG;GACH,aAAa,WAAW,KAAA;GACxB,iBAAiB,YAAY,WAAW,KAAA;GACxC,WAAWD,WAAAA,GAAG,iBAAiB,cAAc,SAAS;GACtD,uBAAuB;GACvB,aAAa;GACb,UAAU;GACV,SAAS;EACX,CAAC;CACH;CAEA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;EACE,GAAI;EACJ,aAAW,WAAW,KAAA;EACtB,WAAW;EACX,uBAAoB;EACpB,aAAU;EACV,UAAU,YAAY;EACtB,SAAS;EACJ;EACC;YAEL;CACK,CAAA;AAEZ,CAAC"}
|
|
@@ -16,7 +16,7 @@ function content(children, loading, startIcon, endIcon) {
|
|
|
16
16
|
!loading ? endIcon : void 0
|
|
17
17
|
] });
|
|
18
18
|
}
|
|
19
|
-
const Button = forwardRef(function Button({ children, className, variant = "outline", size = "md", fullWidth = false, loading = false, startIcon, endIcon, disabled, render, type = "button", ...props }, ref) {
|
|
19
|
+
const Button = forwardRef(function Button({ children, className, variant = "outline", size = "md", fullWidth = false, loading = false, startIcon, endIcon, disabled, onClick: buttonOnClick, render, type = "button", ...props }, ref) {
|
|
20
20
|
const buttonClassName = cx(button({
|
|
21
21
|
variant,
|
|
22
22
|
size,
|
|
@@ -24,7 +24,12 @@ const Button = forwardRef(function Button({ children, className, variant = "outl
|
|
|
24
24
|
}), className);
|
|
25
25
|
const childrenWithIcons = content(children, loading, startIcon, endIcon);
|
|
26
26
|
if (render) {
|
|
27
|
-
const renderedProps = render.props;
|
|
27
|
+
const renderedProps = render.props ?? {};
|
|
28
|
+
const renderedOnClick = renderedProps.onClick;
|
|
29
|
+
const handleRenderedClick = disabled || loading ? (event) => event.preventDefault() : (event) => {
|
|
30
|
+
renderedOnClick?.(event);
|
|
31
|
+
if (!event.defaultPrevented) buttonOnClick?.(event);
|
|
32
|
+
};
|
|
28
33
|
return cloneElement(render, {
|
|
29
34
|
...props,
|
|
30
35
|
"aria-busy": loading || void 0,
|
|
@@ -33,7 +38,7 @@ const Button = forwardRef(function Button({ children, className, variant = "outl
|
|
|
33
38
|
"data-jaci-component": "button",
|
|
34
39
|
"data-slot": "button",
|
|
35
40
|
children: childrenWithIcons,
|
|
36
|
-
onClick:
|
|
41
|
+
onClick: handleRenderedClick
|
|
37
42
|
});
|
|
38
43
|
}
|
|
39
44
|
return /* @__PURE__ */ jsx("button", {
|
|
@@ -43,6 +48,7 @@ const Button = forwardRef(function Button({ children, className, variant = "outl
|
|
|
43
48
|
"data-jaci-component": "button",
|
|
44
49
|
"data-slot": "button",
|
|
45
50
|
disabled: disabled || loading,
|
|
51
|
+
onClick: buttonOnClick,
|
|
46
52
|
ref,
|
|
47
53
|
type,
|
|
48
54
|
children: childrenWithIcons
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","names":[],"sources":["../../../src/components/button/button.tsx"],"sourcesContent":["\"use client\";\n\nimport { cloneElement, forwardRef } from \"react\";\nimport type {
|
|
1
|
+
{"version":3,"file":"button.js","names":[],"sources":["../../../src/components/button/button.tsx"],"sourcesContent":["\"use client\";\n\nimport { cloneElement, forwardRef } from \"react\";\nimport type {\n ComponentPropsWithoutRef,\n MouseEvent,\n MouseEventHandler,\n ReactElement,\n ReactNode,\n} from \"react\";\n\nimport { cx } from \"../../styled-system/css\";\nimport { button } from \"../../styled-system/recipes\";\nimport { Spinner } from \"../layout\";\n\ntype RenderableButtonProps = Record<string, unknown> & {\n children?: ReactNode | undefined;\n className?: string | undefined;\n onClick?: MouseEventHandler<HTMLElement> | undefined;\n};\n\nexport interface ButtonProps\n extends Omit<ComponentPropsWithoutRef<\"button\">, \"color\" | \"children\"> {\n children?: ReactNode;\n variant?: \"outline\" | \"solid\" | \"ghost\" | \"danger\";\n size?: \"sm\" | \"md\" | \"lg\";\n fullWidth?: boolean;\n loading?: boolean;\n startIcon?: ReactNode;\n endIcon?: ReactNode;\n render?: ReactElement<RenderableButtonProps>;\n}\n\nfunction content(children: ReactNode, loading: boolean, startIcon: ReactNode, endIcon: ReactNode) {\n return (\n <>\n {loading ? <Spinner aria-hidden=\"true\" label=\"\" size=\"sm\" /> : startIcon}\n {children}\n {!loading ? endIcon : undefined}\n </>\n );\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n {\n children,\n className,\n variant = \"outline\",\n size = \"md\",\n fullWidth = false,\n loading = false,\n startIcon,\n endIcon,\n disabled,\n onClick: buttonOnClick,\n render,\n type = \"button\",\n ...props\n },\n ref,\n) {\n const buttonClassName = cx(button({ variant, size, fullWidth }), className);\n const childrenWithIcons = content(children, loading, startIcon, endIcon);\n\n if (render) {\n // Some framework adapters (notably React Server Component boundaries) can\n // provide a React element whose props are unavailable until cloning. Keep\n // the render path tolerant of that representation.\n const renderedProps = render.props ?? {};\n const renderedOnClick = renderedProps.onClick as MouseEventHandler<HTMLElement> | undefined;\n const handleRenderedClick: MouseEventHandler<HTMLElement> | undefined =\n disabled || loading\n ? (event) => event.preventDefault()\n : (event) => {\n renderedOnClick?.(event);\n if (!event.defaultPrevented) {\n buttonOnClick?.(event as unknown as MouseEvent<HTMLButtonElement>);\n }\n };\n\n return cloneElement(render, {\n ...props,\n \"aria-busy\": loading || undefined,\n \"aria-disabled\": disabled || loading || undefined,\n className: cx(buttonClassName, renderedProps.className),\n \"data-jaci-component\": \"button\",\n \"data-slot\": \"button\",\n children: childrenWithIcons,\n onClick: handleRenderedClick,\n });\n }\n\n return (\n <button\n {...props}\n aria-busy={loading || undefined}\n className={buttonClassName}\n data-jaci-component=\"button\"\n data-slot=\"button\"\n disabled={disabled || loading}\n onClick={buttonOnClick}\n ref={ref}\n type={type}\n >\n {childrenWithIcons}\n </button>\n );\n});\n"],"mappings":";;;;;;;AAiCA,SAAS,QAAQ,UAAqB,SAAkB,WAAsB,SAAoB;CAChG,OACE,qBAAA,UAAA,EAAA,UAAA;EACG,UAAU,oBAAC,SAAD;GAAS,eAAY;GAAO,OAAM;GAAG,MAAK;EAAM,CAAA,IAAI;EAC9D;EACA,CAAC,UAAU,UAAU,KAAA;CACtB,EAAA,CAAA;AAEN;AAEA,MAAa,SAAS,WAA2C,SAAS,OACxE,EACE,UACA,WACA,UAAU,WACV,OAAO,MACP,YAAY,OACZ,UAAU,OACV,WACA,SACA,UACA,SAAS,eACT,QACA,OAAO,UACP,GAAG,SAEL,KACA;CACA,MAAM,kBAAkB,GAAG,OAAO;EAAE;EAAS;EAAM;CAAU,CAAC,GAAG,SAAS;CAC1E,MAAM,oBAAoB,QAAQ,UAAU,SAAS,WAAW,OAAO;CAEvE,IAAI,QAAQ;EAIV,MAAM,gBAAgB,OAAO,SAAS,CAAC;EACvC,MAAM,kBAAkB,cAAc;EACtC,MAAM,sBACJ,YAAY,WACP,UAAU,MAAM,eAAe,KAC/B,UAAU;GACT,kBAAkB,KAAK;GACvB,IAAI,CAAC,MAAM,kBACT,gBAAgB,KAAiD;EAErE;EAEN,OAAO,aAAa,QAAQ;GAC1B,GAAG;GACH,aAAa,WAAW,KAAA;GACxB,iBAAiB,YAAY,WAAW,KAAA;GACxC,WAAW,GAAG,iBAAiB,cAAc,SAAS;GACtD,uBAAuB;GACvB,aAAa;GACb,UAAU;GACV,SAAS;EACX,CAAC;CACH;CAEA,OACE,oBAAC,UAAD;EACE,GAAI;EACJ,aAAW,WAAW,KAAA;EACtB,WAAW;EACX,uBAAoB;EACpB,aAAU;EACV,UAAU,YAAY;EACtB,SAAS;EACJ;EACC;YAEL;CACK,CAAA;AAEZ,CAAC"}
|
|
@@ -14,6 +14,7 @@ function Finder({ x, y, color, background }) {
|
|
|
14
14
|
"data-slot": "qr-code-eye",
|
|
15
15
|
children: [
|
|
16
16
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
17
|
+
"data-slot": "qr-code-eye-frame",
|
|
17
18
|
fill: color,
|
|
18
19
|
height: "7",
|
|
19
20
|
rx: "1",
|
|
@@ -22,6 +23,7 @@ function Finder({ x, y, color, background }) {
|
|
|
22
23
|
y
|
|
23
24
|
}),
|
|
24
25
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
26
|
+
"data-slot": "qr-code-eye-cutout",
|
|
25
27
|
fill: background,
|
|
26
28
|
height: "5",
|
|
27
29
|
rx: "0.75",
|
|
@@ -30,6 +32,7 @@ function Finder({ x, y, color, background }) {
|
|
|
30
32
|
y: y + 1
|
|
31
33
|
}),
|
|
32
34
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
35
|
+
"data-slot": "qr-code-eyeball",
|
|
33
36
|
fill: color,
|
|
34
37
|
height: "3",
|
|
35
38
|
rx: "0.5",
|
|
@@ -40,66 +43,108 @@ function Finder({ x, y, color, background }) {
|
|
|
40
43
|
]
|
|
41
44
|
});
|
|
42
45
|
}
|
|
43
|
-
|
|
46
|
+
function escapeXml(value) {
|
|
47
|
+
return value.replace(/[&<>'"]/g, (character) => {
|
|
48
|
+
return {
|
|
49
|
+
"&": "&",
|
|
50
|
+
"<": "<",
|
|
51
|
+
">": ">",
|
|
52
|
+
"'": "'",
|
|
53
|
+
"\"": """
|
|
54
|
+
}[character] ?? character;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function createDownloadSvg({ background, dots, foreground, finderBackground, label, margin, moduleCount }) {
|
|
58
|
+
const viewBoxSize = moduleCount + margin * 2;
|
|
59
|
+
const backgroundMarkup = background === "transparent" ? "" : `<rect fill="${escapeXml(background)}" height="${viewBoxSize}" width="${viewBoxSize}" x="0" y="0"/>`;
|
|
60
|
+
const dotsMarkup = dots.map(([row, column]) => `<circle cx="${margin + column + .5}" cy="${margin + row + .5}" fill="${escapeXml(foreground)}" r="0.43"/>`).join("");
|
|
61
|
+
const finderMarkup = (x, y) => `<g><rect fill="${escapeXml(foreground)}" height="7" rx="1" width="7" x="${x}" y="${y}"/><rect fill="${escapeXml(finderBackground)}" height="5" rx="0.75" width="5" x="${x + 1}" y="${y + 1}"/><rect fill="${escapeXml(foreground)}" height="3" rx="0.5" width="3" x="${x + 2}" y="${y + 2}"/></g>`;
|
|
62
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" aria-label="${escapeXml(label)}" role="img" viewBox="0 0 ${viewBoxSize} ${viewBoxSize}">${backgroundMarkup}${dotsMarkup}${finderMarkup(margin, margin)}${finderMarkup(margin + moduleCount - 7, margin)}${finderMarkup(margin, margin + moduleCount - 7)}</svg>`;
|
|
63
|
+
}
|
|
64
|
+
const QRCode = (0, react.forwardRef)(function QRCode({ background = "#ffffff", className, download = false, downloadLabel = "Download QR code", errorCorrectionLevel = "Q", fallback, foreground = "#18181b", label = "QR code", margin = 2, size = 192, style, value, ...props }, ref) {
|
|
44
65
|
const safeSize = Number.isFinite(size) && size > 0 ? size : 192;
|
|
45
66
|
const safeMargin = Number.isFinite(margin) && margin >= 0 ? Math.floor(margin) : 2;
|
|
46
|
-
const finderBackground = background === "transparent" ? "
|
|
67
|
+
const finderBackground = background === "transparent" ? "var(--jaci-colors-surface-raised)" : background;
|
|
47
68
|
try {
|
|
48
69
|
const code = qrcode.create(value, { errorCorrectionLevel });
|
|
49
70
|
const moduleCount = code.modules.size;
|
|
50
71
|
const viewBoxSize = moduleCount + safeMargin * 2;
|
|
51
72
|
const modules = [];
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
const dotCoordinates = [];
|
|
74
|
+
for (let row = 0; row < moduleCount; row += 1) for (let column = 0; column < moduleCount; column += 1) if (code.modules.get(row, column) && !isFinderCell(row, column, moduleCount)) {
|
|
75
|
+
dotCoordinates.push([row, column]);
|
|
76
|
+
modules.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
77
|
+
cx: safeMargin + column + .5,
|
|
78
|
+
cy: safeMargin + row + .5,
|
|
79
|
+
"data-slot": "qr-code-dot",
|
|
80
|
+
fill: foreground,
|
|
81
|
+
r: "0.43"
|
|
82
|
+
}, `${row}-${column}`));
|
|
83
|
+
}
|
|
84
|
+
const downloadHref = download && `data:image/svg+xml;charset=utf-8,${encodeURIComponent(createDownloadSvg({
|
|
85
|
+
background,
|
|
86
|
+
dots: dotCoordinates,
|
|
87
|
+
foreground,
|
|
88
|
+
finderBackground: background === "transparent" ? "#ffffff" : background,
|
|
89
|
+
label,
|
|
90
|
+
margin: safeMargin,
|
|
91
|
+
moduleCount
|
|
92
|
+
}))}`;
|
|
93
|
+
const downloadFilename = typeof download === "string" ? download : "qrcode.svg";
|
|
94
|
+
const visualCode = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
95
|
+
background !== "transparent" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
96
|
+
fill: background,
|
|
97
|
+
height: viewBoxSize,
|
|
98
|
+
width: viewBoxSize,
|
|
99
|
+
x: "0",
|
|
100
|
+
y: "0"
|
|
101
|
+
}) : null,
|
|
102
|
+
modules,
|
|
103
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Finder, {
|
|
104
|
+
background: finderBackground,
|
|
105
|
+
color: foreground,
|
|
106
|
+
x: safeMargin,
|
|
107
|
+
y: safeMargin
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Finder, {
|
|
110
|
+
background: finderBackground,
|
|
111
|
+
color: foreground,
|
|
112
|
+
x: safeMargin + moduleCount - 7,
|
|
113
|
+
y: safeMargin
|
|
114
|
+
}),
|
|
115
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Finder, {
|
|
116
|
+
background: finderBackground,
|
|
117
|
+
color: foreground,
|
|
118
|
+
x: safeMargin,
|
|
119
|
+
y: safeMargin + moduleCount - 7
|
|
120
|
+
})
|
|
121
|
+
] });
|
|
122
|
+
const svg = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
60
123
|
...props,
|
|
61
124
|
ref,
|
|
62
|
-
"aria-
|
|
125
|
+
"aria-hidden": downloadHref ? true : void 0,
|
|
126
|
+
"aria-label": downloadHref ? void 0 : label,
|
|
63
127
|
className: require_cx.cx(require_qr_code.qrCode(), className),
|
|
64
128
|
"data-dot-shape": "circle",
|
|
129
|
+
"data-download": download ? "true" : void 0,
|
|
65
130
|
"data-eye-shape": "rounded-square",
|
|
66
131
|
"data-jaci-component": "qr-code",
|
|
67
132
|
"data-slot": "qr-code",
|
|
68
133
|
height: safeSize,
|
|
69
|
-
role: "img",
|
|
134
|
+
role: downloadHref ? void 0 : "img",
|
|
70
135
|
style,
|
|
71
136
|
viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`,
|
|
72
137
|
width: safeSize,
|
|
73
|
-
children: [
|
|
74
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("title", { children: label }),
|
|
75
|
-
background !== "transparent" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
76
|
-
fill: background,
|
|
77
|
-
height: viewBoxSize,
|
|
78
|
-
width: viewBoxSize,
|
|
79
|
-
x: "0",
|
|
80
|
-
y: "0"
|
|
81
|
-
}) : null,
|
|
82
|
-
modules,
|
|
83
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Finder, {
|
|
84
|
-
background: finderBackground,
|
|
85
|
-
color: foreground,
|
|
86
|
-
x: safeMargin,
|
|
87
|
-
y: safeMargin
|
|
88
|
-
}),
|
|
89
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Finder, {
|
|
90
|
-
background: finderBackground,
|
|
91
|
-
color: foreground,
|
|
92
|
-
x: safeMargin + moduleCount - 7,
|
|
93
|
-
y: safeMargin
|
|
94
|
-
}),
|
|
95
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Finder, {
|
|
96
|
-
background: finderBackground,
|
|
97
|
-
color: foreground,
|
|
98
|
-
x: safeMargin,
|
|
99
|
-
y: safeMargin + moduleCount - 7
|
|
100
|
-
})
|
|
101
|
-
]
|
|
138
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("title", { children: label }), visualCode]
|
|
102
139
|
});
|
|
140
|
+
return downloadHref ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
141
|
+
"aria-label": downloadLabel,
|
|
142
|
+
"data-jaci-component": "qr-code-download",
|
|
143
|
+
"data-slot": "qr-code-download",
|
|
144
|
+
download: downloadFilename,
|
|
145
|
+
href: downloadHref,
|
|
146
|
+
children: svg
|
|
147
|
+
}) : svg;
|
|
103
148
|
} catch {
|
|
104
149
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
105
150
|
"aria-label": label,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr-code.cjs","names":["QRCodeEncoder","cx","qrCode"],"sources":["../../../src/components/qr-code/qr-code.tsx"],"sourcesContent":["import * as QRCodeEncoder from \"qrcode\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { cx } from \"../../styled-system/css\";\nimport { qrCode } from \"../../styled-system/recipes\";\n\nexport type QRCodeErrorCorrectionLevel = \"L\" | \"M\" | \"Q\" | \"H\";\n\nexport interface QRCodeProps extends Omit<ComponentPropsWithoutRef<\"svg\">, \"children\"> {\n value: string;\n size?: number;\n margin?: number;\n errorCorrectionLevel?: QRCodeErrorCorrectionLevel;\n foreground?: string;\n background?: string;\n label?: string;\n fallback?: ReactNode;\n}\n\nfunction isFinderCell(row: number, column: number, size: number) {\n return (\n (row < 7 && column < 7) || (row < 7 && column >= size - 7) || (row >= size - 7 && column < 7)\n );\n}\n\nfunction Finder({\n x,\n y,\n color,\n background,\n}: {\n x: number;\n y: number;\n color: string;\n background: string;\n}) {\n return (\n <g data-slot=\"qr-code-eye\">\n <rect fill={color} height=\"7\" rx=\"1\" width=\"7\" x={x} y={y} />\n <rect fill={background} height=\"5\" rx=\"0.75\" width=\"5\" x={x + 1} y={y + 1} />\n <rect fill={color} height=\"3\" rx=\"0.5\" width=\"3\" x={x + 2} y={y + 2} />\n </g>\n );\n}\n\nexport const QRCode = forwardRef<SVGSVGElement, QRCodeProps>(function QRCode(\n {\n background = \"transparent\",\n className,\n errorCorrectionLevel = \"Q\",\n fallback,\n foreground = \"currentColor\",\n label = \"QR code\",\n margin = 2,\n size = 192,\n style,\n value,\n ...props\n },\n ref,\n) {\n const safeSize = Number.isFinite(size) && size > 0 ? size : 192;\n const safeMargin = Number.isFinite(margin) && margin >= 0 ? Math.floor(margin) : 2;\n // Finder patterns need a contrasting quiet area between the frame and the\n // eyeball. Keep the overall SVG transparent by default, but use a white\n // cutout when no background was supplied so the code remains scannable.\n const finderBackground = background === \"transparent\" ? \"white\" : background;\n\n try {\n const code = QRCodeEncoder.create(value, { errorCorrectionLevel });\n const moduleCount = code.modules.size;\n const viewBoxSize = moduleCount + safeMargin * 2;\n const modules: ReactNode[] = [];\n\n for (let row = 0; row < moduleCount; row += 1) {\n for (let column = 0; column < moduleCount; column += 1) {\n if (code.modules.get(row, column) && !isFinderCell(row, column, moduleCount)) {\n modules.push(\n <circle\n cx={safeMargin + column + 0.5}\n cy={safeMargin + row + 0.5}\n data-slot=\"qr-code-dot\"\n fill={foreground}\n key={`${row}-${column}`}\n r=\"0.43\"\n />,\n );\n }\n }\n }\n\n return (\n <svg\n {...props}\n ref={ref}\n aria-label={label}\n className={cx(qrCode(), className)}\n data-dot-shape=\"circle\"\n data-eye-shape=\"rounded-square\"\n data-jaci-component=\"qr-code\"\n data-slot=\"qr-code\"\n height={safeSize}\n role=\"img\"\n style={style}\n viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}\n width={safeSize}\n >\n <title>{label}</title>\n {background !== \"transparent\" ? (\n <rect fill={background} height={viewBoxSize} width={viewBoxSize} x=\"0\" y=\"0\" />\n ) : null}\n {modules}\n <Finder background={finderBackground} color={foreground} x={safeMargin} y={safeMargin} />\n <Finder\n background={finderBackground}\n color={foreground}\n x={safeMargin + moduleCount - 7}\n y={safeMargin}\n />\n <Finder\n background={finderBackground}\n color={foreground}\n x={safeMargin}\n y={safeMargin + moduleCount - 7}\n />\n </svg>\n );\n } catch {\n return (\n <span\n aria-label={label}\n className={cx(qrCode(), className)}\n data-jaci-component=\"qr-code\"\n data-slot=\"qr-code\"\n data-status=\"error\"\n role=\"img\"\n >\n {fallback ?? \"Unable to generate QR code\"}\n </span>\n );\n }\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"qr-code.cjs","names":["QRCodeEncoder","cx","qrCode"],"sources":["../../../src/components/qr-code/qr-code.tsx"],"sourcesContent":["import * as QRCodeEncoder from \"qrcode\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { cx } from \"../../styled-system/css\";\nimport { qrCode } from \"../../styled-system/recipes\";\n\nexport type QRCodeErrorCorrectionLevel = \"L\" | \"M\" | \"Q\" | \"H\";\n\nexport interface QRCodeProps\n extends Omit<ComponentPropsWithoutRef<\"svg\">, \"children\" | \"download\"> {\n value: string;\n size?: number;\n margin?: number;\n errorCorrectionLevel?: QRCodeErrorCorrectionLevel;\n foreground?: string;\n background?: string;\n label?: string;\n fallback?: ReactNode;\n /** Enables a native SVG download link inside the rendered code. */\n download?: boolean | string;\n downloadLabel?: string;\n}\n\nfunction isFinderCell(row: number, column: number, size: number) {\n return (\n (row < 7 && column < 7) || (row < 7 && column >= size - 7) || (row >= size - 7 && column < 7)\n );\n}\n\nfunction Finder({\n x,\n y,\n color,\n background,\n}: {\n x: number;\n y: number;\n color: string;\n background: string;\n}) {\n return (\n <g data-slot=\"qr-code-eye\">\n <rect data-slot=\"qr-code-eye-frame\" fill={color} height=\"7\" rx=\"1\" width=\"7\" x={x} y={y} />\n <rect\n data-slot=\"qr-code-eye-cutout\"\n fill={background}\n height=\"5\"\n rx=\"0.75\"\n width=\"5\"\n x={x + 1}\n y={y + 1}\n />\n <rect\n data-slot=\"qr-code-eyeball\"\n fill={color}\n height=\"3\"\n rx=\"0.5\"\n width=\"3\"\n x={x + 2}\n y={y + 2}\n />\n </g>\n );\n}\n\nfunction escapeXml(value: string) {\n return value.replace(/[&<>'\"]/g, (character) => {\n const entities: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n \"'\": \"'\",\n '\"': \""\",\n };\n return entities[character] ?? character;\n });\n}\n\nfunction createDownloadSvg({\n background,\n dots,\n foreground,\n finderBackground,\n label,\n margin,\n moduleCount,\n}: {\n background: string;\n dots: readonly [number, number][];\n foreground: string;\n finderBackground: string;\n label: string;\n margin: number;\n moduleCount: number;\n}) {\n const viewBoxSize = moduleCount + margin * 2;\n const backgroundMarkup =\n background === \"transparent\"\n ? \"\"\n : `<rect fill=\"${escapeXml(background)}\" height=\"${viewBoxSize}\" width=\"${viewBoxSize}\" x=\"0\" y=\"0\"/>`;\n const dotsMarkup = dots\n .map(\n ([row, column]) =>\n `<circle cx=\"${margin + column + 0.5}\" cy=\"${margin + row + 0.5}\" fill=\"${escapeXml(foreground)}\" r=\"0.43\"/>`,\n )\n .join(\"\");\n const finderMarkup = (x: number, y: number) =>\n `<g><rect fill=\"${escapeXml(foreground)}\" height=\"7\" rx=\"1\" width=\"7\" x=\"${x}\" y=\"${y}\"/><rect fill=\"${escapeXml(finderBackground)}\" height=\"5\" rx=\"0.75\" width=\"5\" x=\"${x + 1}\" y=\"${y + 1}\"/><rect fill=\"${escapeXml(foreground)}\" height=\"3\" rx=\"0.5\" width=\"3\" x=\"${x + 2}\" y=\"${y + 2}\"/></g>`;\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" aria-label=\"${escapeXml(label)}\" role=\"img\" viewBox=\"0 0 ${viewBoxSize} ${viewBoxSize}\">${backgroundMarkup}${dotsMarkup}${finderMarkup(margin, margin)}${finderMarkup(margin + moduleCount - 7, margin)}${finderMarkup(margin, margin + moduleCount - 7)}</svg>`;\n}\n\nexport const QRCode = forwardRef<SVGSVGElement, QRCodeProps>(function QRCode(\n {\n // A QR code needs a deterministic high-contrast base. Inheriting\n // `currentColor` or a transparent surface can make finder layers merge\n // in dark scopes, so the defaults intentionally remain black on white.\n background = \"#ffffff\",\n className,\n download = false,\n downloadLabel = \"Download QR code\",\n errorCorrectionLevel = \"Q\",\n fallback,\n foreground = \"#18181b\",\n label = \"QR code\",\n margin = 2,\n size = 192,\n style,\n value,\n ...props\n },\n ref,\n) {\n const safeSize = Number.isFinite(size) && size > 0 ? size : 192;\n const safeMargin = Number.isFinite(margin) && margin >= 0 ? Math.floor(margin) : 2;\n const finderBackground =\n background === \"transparent\" ? \"var(--jaci-colors-surface-raised)\" : background;\n\n try {\n const code = QRCodeEncoder.create(value, { errorCorrectionLevel });\n const moduleCount = code.modules.size;\n const viewBoxSize = moduleCount + safeMargin * 2;\n const modules: ReactNode[] = [];\n const dotCoordinates: [number, number][] = [];\n\n for (let row = 0; row < moduleCount; row += 1) {\n for (let column = 0; column < moduleCount; column += 1) {\n if (code.modules.get(row, column) && !isFinderCell(row, column, moduleCount)) {\n dotCoordinates.push([row, column]);\n modules.push(\n <circle\n cx={safeMargin + column + 0.5}\n cy={safeMargin + row + 0.5}\n data-slot=\"qr-code-dot\"\n fill={foreground}\n key={`${row}-${column}`}\n r=\"0.43\"\n />,\n );\n }\n }\n }\n\n const downloadHref =\n download &&\n `data:image/svg+xml;charset=utf-8,${encodeURIComponent(\n createDownloadSvg({\n background,\n dots: dotCoordinates,\n foreground,\n finderBackground: background === \"transparent\" ? \"#ffffff\" : background,\n label,\n margin: safeMargin,\n moduleCount,\n }),\n )}`;\n const downloadFilename = typeof download === \"string\" ? download : \"qrcode.svg\";\n const visualCode = (\n <>\n {background !== \"transparent\" ? (\n <rect fill={background} height={viewBoxSize} width={viewBoxSize} x=\"0\" y=\"0\" />\n ) : null}\n {modules}\n <Finder background={finderBackground} color={foreground} x={safeMargin} y={safeMargin} />\n <Finder\n background={finderBackground}\n color={foreground}\n x={safeMargin + moduleCount - 7}\n y={safeMargin}\n />\n <Finder\n background={finderBackground}\n color={foreground}\n x={safeMargin}\n y={safeMargin + moduleCount - 7}\n />\n </>\n );\n\n const svg = (\n <svg\n {...props}\n ref={ref}\n aria-hidden={downloadHref ? true : undefined}\n aria-label={downloadHref ? undefined : label}\n className={cx(qrCode(), className)}\n data-dot-shape=\"circle\"\n data-download={download ? \"true\" : undefined}\n data-eye-shape=\"rounded-square\"\n data-jaci-component=\"qr-code\"\n data-slot=\"qr-code\"\n height={safeSize}\n role={downloadHref ? undefined : \"img\"}\n style={style}\n viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}\n width={safeSize}\n >\n <title>{label}</title>\n {visualCode}\n </svg>\n );\n\n return downloadHref ? (\n <a\n aria-label={downloadLabel}\n data-jaci-component=\"qr-code-download\"\n data-slot=\"qr-code-download\"\n download={downloadFilename}\n href={downloadHref}\n >\n {svg}\n </a>\n ) : (\n svg\n );\n } catch {\n return (\n <span\n aria-label={label}\n className={cx(qrCode(), className)}\n data-jaci-component=\"qr-code\"\n data-slot=\"qr-code\"\n data-status=\"error\"\n role=\"img\"\n >\n {fallback ?? \"Unable to generate QR code\"}\n </span>\n );\n }\n});\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
2
|
//#region src/components/qr-code/qr-code.d.ts
|
|
3
3
|
type QRCodeErrorCorrectionLevel = "L" | "M" | "Q" | "H";
|
|
4
|
-
interface QRCodeProps extends Omit<ComponentPropsWithoutRef<"svg">, "children"> {
|
|
4
|
+
interface QRCodeProps extends Omit<ComponentPropsWithoutRef<"svg">, "children" | "download"> {
|
|
5
5
|
value: string;
|
|
6
6
|
size?: number;
|
|
7
7
|
margin?: number;
|
|
@@ -10,6 +10,9 @@ interface QRCodeProps extends Omit<ComponentPropsWithoutRef<"svg">, "children">
|
|
|
10
10
|
background?: string;
|
|
11
11
|
label?: string;
|
|
12
12
|
fallback?: ReactNode;
|
|
13
|
+
/** Enables a native SVG download link inside the rendered code. */
|
|
14
|
+
download?: boolean | string;
|
|
15
|
+
downloadLabel?: string;
|
|
13
16
|
}
|
|
14
17
|
declare const QRCode: import("react").ForwardRefExoticComponent<QRCodeProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
15
18
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
2
|
//#region src/components/qr-code/qr-code.d.ts
|
|
3
3
|
type QRCodeErrorCorrectionLevel = "L" | "M" | "Q" | "H";
|
|
4
|
-
interface QRCodeProps extends Omit<ComponentPropsWithoutRef<"svg">, "children"> {
|
|
4
|
+
interface QRCodeProps extends Omit<ComponentPropsWithoutRef<"svg">, "children" | "download"> {
|
|
5
5
|
value: string;
|
|
6
6
|
size?: number;
|
|
7
7
|
margin?: number;
|
|
@@ -10,6 +10,9 @@ interface QRCodeProps extends Omit<ComponentPropsWithoutRef<"svg">, "children">
|
|
|
10
10
|
background?: string;
|
|
11
11
|
label?: string;
|
|
12
12
|
fallback?: ReactNode;
|
|
13
|
+
/** Enables a native SVG download link inside the rendered code. */
|
|
14
|
+
download?: boolean | string;
|
|
15
|
+
downloadLabel?: string;
|
|
13
16
|
}
|
|
14
17
|
declare const QRCode: import("react").ForwardRefExoticComponent<QRCodeProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
15
18
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cx } from "../../styled-system/css/cx.js";
|
|
2
2
|
import { qrCode } from "../../styled-system/recipes/qr-code.js";
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import * as QRCodeEncoder from "qrcode";
|
|
6
6
|
//#region src/components/qr-code/qr-code.tsx
|
|
7
7
|
function isFinderCell(row, column, size) {
|
|
@@ -12,6 +12,7 @@ function Finder({ x, y, color, background }) {
|
|
|
12
12
|
"data-slot": "qr-code-eye",
|
|
13
13
|
children: [
|
|
14
14
|
/* @__PURE__ */ jsx("rect", {
|
|
15
|
+
"data-slot": "qr-code-eye-frame",
|
|
15
16
|
fill: color,
|
|
16
17
|
height: "7",
|
|
17
18
|
rx: "1",
|
|
@@ -20,6 +21,7 @@ function Finder({ x, y, color, background }) {
|
|
|
20
21
|
y
|
|
21
22
|
}),
|
|
22
23
|
/* @__PURE__ */ jsx("rect", {
|
|
24
|
+
"data-slot": "qr-code-eye-cutout",
|
|
23
25
|
fill: background,
|
|
24
26
|
height: "5",
|
|
25
27
|
rx: "0.75",
|
|
@@ -28,6 +30,7 @@ function Finder({ x, y, color, background }) {
|
|
|
28
30
|
y: y + 1
|
|
29
31
|
}),
|
|
30
32
|
/* @__PURE__ */ jsx("rect", {
|
|
33
|
+
"data-slot": "qr-code-eyeball",
|
|
31
34
|
fill: color,
|
|
32
35
|
height: "3",
|
|
33
36
|
rx: "0.5",
|
|
@@ -38,66 +41,108 @@ function Finder({ x, y, color, background }) {
|
|
|
38
41
|
]
|
|
39
42
|
});
|
|
40
43
|
}
|
|
41
|
-
|
|
44
|
+
function escapeXml(value) {
|
|
45
|
+
return value.replace(/[&<>'"]/g, (character) => {
|
|
46
|
+
return {
|
|
47
|
+
"&": "&",
|
|
48
|
+
"<": "<",
|
|
49
|
+
">": ">",
|
|
50
|
+
"'": "'",
|
|
51
|
+
"\"": """
|
|
52
|
+
}[character] ?? character;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function createDownloadSvg({ background, dots, foreground, finderBackground, label, margin, moduleCount }) {
|
|
56
|
+
const viewBoxSize = moduleCount + margin * 2;
|
|
57
|
+
const backgroundMarkup = background === "transparent" ? "" : `<rect fill="${escapeXml(background)}" height="${viewBoxSize}" width="${viewBoxSize}" x="0" y="0"/>`;
|
|
58
|
+
const dotsMarkup = dots.map(([row, column]) => `<circle cx="${margin + column + .5}" cy="${margin + row + .5}" fill="${escapeXml(foreground)}" r="0.43"/>`).join("");
|
|
59
|
+
const finderMarkup = (x, y) => `<g><rect fill="${escapeXml(foreground)}" height="7" rx="1" width="7" x="${x}" y="${y}"/><rect fill="${escapeXml(finderBackground)}" height="5" rx="0.75" width="5" x="${x + 1}" y="${y + 1}"/><rect fill="${escapeXml(foreground)}" height="3" rx="0.5" width="3" x="${x + 2}" y="${y + 2}"/></g>`;
|
|
60
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" aria-label="${escapeXml(label)}" role="img" viewBox="0 0 ${viewBoxSize} ${viewBoxSize}">${backgroundMarkup}${dotsMarkup}${finderMarkup(margin, margin)}${finderMarkup(margin + moduleCount - 7, margin)}${finderMarkup(margin, margin + moduleCount - 7)}</svg>`;
|
|
61
|
+
}
|
|
62
|
+
const QRCode = forwardRef(function QRCode({ background = "#ffffff", className, download = false, downloadLabel = "Download QR code", errorCorrectionLevel = "Q", fallback, foreground = "#18181b", label = "QR code", margin = 2, size = 192, style, value, ...props }, ref) {
|
|
42
63
|
const safeSize = Number.isFinite(size) && size > 0 ? size : 192;
|
|
43
64
|
const safeMargin = Number.isFinite(margin) && margin >= 0 ? Math.floor(margin) : 2;
|
|
44
|
-
const finderBackground = background === "transparent" ? "
|
|
65
|
+
const finderBackground = background === "transparent" ? "var(--jaci-colors-surface-raised)" : background;
|
|
45
66
|
try {
|
|
46
67
|
const code = QRCodeEncoder.create(value, { errorCorrectionLevel });
|
|
47
68
|
const moduleCount = code.modules.size;
|
|
48
69
|
const viewBoxSize = moduleCount + safeMargin * 2;
|
|
49
70
|
const modules = [];
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
const dotCoordinates = [];
|
|
72
|
+
for (let row = 0; row < moduleCount; row += 1) for (let column = 0; column < moduleCount; column += 1) if (code.modules.get(row, column) && !isFinderCell(row, column, moduleCount)) {
|
|
73
|
+
dotCoordinates.push([row, column]);
|
|
74
|
+
modules.push(/* @__PURE__ */ jsx("circle", {
|
|
75
|
+
cx: safeMargin + column + .5,
|
|
76
|
+
cy: safeMargin + row + .5,
|
|
77
|
+
"data-slot": "qr-code-dot",
|
|
78
|
+
fill: foreground,
|
|
79
|
+
r: "0.43"
|
|
80
|
+
}, `${row}-${column}`));
|
|
81
|
+
}
|
|
82
|
+
const downloadHref = download && `data:image/svg+xml;charset=utf-8,${encodeURIComponent(createDownloadSvg({
|
|
83
|
+
background,
|
|
84
|
+
dots: dotCoordinates,
|
|
85
|
+
foreground,
|
|
86
|
+
finderBackground: background === "transparent" ? "#ffffff" : background,
|
|
87
|
+
label,
|
|
88
|
+
margin: safeMargin,
|
|
89
|
+
moduleCount
|
|
90
|
+
}))}`;
|
|
91
|
+
const downloadFilename = typeof download === "string" ? download : "qrcode.svg";
|
|
92
|
+
const visualCode = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
93
|
+
background !== "transparent" ? /* @__PURE__ */ jsx("rect", {
|
|
94
|
+
fill: background,
|
|
95
|
+
height: viewBoxSize,
|
|
96
|
+
width: viewBoxSize,
|
|
97
|
+
x: "0",
|
|
98
|
+
y: "0"
|
|
99
|
+
}) : null,
|
|
100
|
+
modules,
|
|
101
|
+
/* @__PURE__ */ jsx(Finder, {
|
|
102
|
+
background: finderBackground,
|
|
103
|
+
color: foreground,
|
|
104
|
+
x: safeMargin,
|
|
105
|
+
y: safeMargin
|
|
106
|
+
}),
|
|
107
|
+
/* @__PURE__ */ jsx(Finder, {
|
|
108
|
+
background: finderBackground,
|
|
109
|
+
color: foreground,
|
|
110
|
+
x: safeMargin + moduleCount - 7,
|
|
111
|
+
y: safeMargin
|
|
112
|
+
}),
|
|
113
|
+
/* @__PURE__ */ jsx(Finder, {
|
|
114
|
+
background: finderBackground,
|
|
115
|
+
color: foreground,
|
|
116
|
+
x: safeMargin,
|
|
117
|
+
y: safeMargin + moduleCount - 7
|
|
118
|
+
})
|
|
119
|
+
] });
|
|
120
|
+
const svg = /* @__PURE__ */ jsxs("svg", {
|
|
58
121
|
...props,
|
|
59
122
|
ref,
|
|
60
|
-
"aria-
|
|
123
|
+
"aria-hidden": downloadHref ? true : void 0,
|
|
124
|
+
"aria-label": downloadHref ? void 0 : label,
|
|
61
125
|
className: cx(qrCode(), className),
|
|
62
126
|
"data-dot-shape": "circle",
|
|
127
|
+
"data-download": download ? "true" : void 0,
|
|
63
128
|
"data-eye-shape": "rounded-square",
|
|
64
129
|
"data-jaci-component": "qr-code",
|
|
65
130
|
"data-slot": "qr-code",
|
|
66
131
|
height: safeSize,
|
|
67
|
-
role: "img",
|
|
132
|
+
role: downloadHref ? void 0 : "img",
|
|
68
133
|
style,
|
|
69
134
|
viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`,
|
|
70
135
|
width: safeSize,
|
|
71
|
-
children: [
|
|
72
|
-
/* @__PURE__ */ jsx("title", { children: label }),
|
|
73
|
-
background !== "transparent" ? /* @__PURE__ */ jsx("rect", {
|
|
74
|
-
fill: background,
|
|
75
|
-
height: viewBoxSize,
|
|
76
|
-
width: viewBoxSize,
|
|
77
|
-
x: "0",
|
|
78
|
-
y: "0"
|
|
79
|
-
}) : null,
|
|
80
|
-
modules,
|
|
81
|
-
/* @__PURE__ */ jsx(Finder, {
|
|
82
|
-
background: finderBackground,
|
|
83
|
-
color: foreground,
|
|
84
|
-
x: safeMargin,
|
|
85
|
-
y: safeMargin
|
|
86
|
-
}),
|
|
87
|
-
/* @__PURE__ */ jsx(Finder, {
|
|
88
|
-
background: finderBackground,
|
|
89
|
-
color: foreground,
|
|
90
|
-
x: safeMargin + moduleCount - 7,
|
|
91
|
-
y: safeMargin
|
|
92
|
-
}),
|
|
93
|
-
/* @__PURE__ */ jsx(Finder, {
|
|
94
|
-
background: finderBackground,
|
|
95
|
-
color: foreground,
|
|
96
|
-
x: safeMargin,
|
|
97
|
-
y: safeMargin + moduleCount - 7
|
|
98
|
-
})
|
|
99
|
-
]
|
|
136
|
+
children: [/* @__PURE__ */ jsx("title", { children: label }), visualCode]
|
|
100
137
|
});
|
|
138
|
+
return downloadHref ? /* @__PURE__ */ jsx("a", {
|
|
139
|
+
"aria-label": downloadLabel,
|
|
140
|
+
"data-jaci-component": "qr-code-download",
|
|
141
|
+
"data-slot": "qr-code-download",
|
|
142
|
+
download: downloadFilename,
|
|
143
|
+
href: downloadHref,
|
|
144
|
+
children: svg
|
|
145
|
+
}) : svg;
|
|
101
146
|
} catch {
|
|
102
147
|
return /* @__PURE__ */ jsx("span", {
|
|
103
148
|
"aria-label": label,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr-code.js","names":[],"sources":["../../../src/components/qr-code/qr-code.tsx"],"sourcesContent":["import * as QRCodeEncoder from \"qrcode\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { cx } from \"../../styled-system/css\";\nimport { qrCode } from \"../../styled-system/recipes\";\n\nexport type QRCodeErrorCorrectionLevel = \"L\" | \"M\" | \"Q\" | \"H\";\n\nexport interface QRCodeProps extends Omit<ComponentPropsWithoutRef<\"svg\">, \"children\"> {\n value: string;\n size?: number;\n margin?: number;\n errorCorrectionLevel?: QRCodeErrorCorrectionLevel;\n foreground?: string;\n background?: string;\n label?: string;\n fallback?: ReactNode;\n}\n\nfunction isFinderCell(row: number, column: number, size: number) {\n return (\n (row < 7 && column < 7) || (row < 7 && column >= size - 7) || (row >= size - 7 && column < 7)\n );\n}\n\nfunction Finder({\n x,\n y,\n color,\n background,\n}: {\n x: number;\n y: number;\n color: string;\n background: string;\n}) {\n return (\n <g data-slot=\"qr-code-eye\">\n <rect fill={color} height=\"7\" rx=\"1\" width=\"7\" x={x} y={y} />\n <rect fill={background} height=\"5\" rx=\"0.75\" width=\"5\" x={x + 1} y={y + 1} />\n <rect fill={color} height=\"3\" rx=\"0.5\" width=\"3\" x={x + 2} y={y + 2} />\n </g>\n );\n}\n\nexport const QRCode = forwardRef<SVGSVGElement, QRCodeProps>(function QRCode(\n {\n background = \"transparent\",\n className,\n errorCorrectionLevel = \"Q\",\n fallback,\n foreground = \"currentColor\",\n label = \"QR code\",\n margin = 2,\n size = 192,\n style,\n value,\n ...props\n },\n ref,\n) {\n const safeSize = Number.isFinite(size) && size > 0 ? size : 192;\n const safeMargin = Number.isFinite(margin) && margin >= 0 ? Math.floor(margin) : 2;\n // Finder patterns need a contrasting quiet area between the frame and the\n // eyeball. Keep the overall SVG transparent by default, but use a white\n // cutout when no background was supplied so the code remains scannable.\n const finderBackground = background === \"transparent\" ? \"white\" : background;\n\n try {\n const code = QRCodeEncoder.create(value, { errorCorrectionLevel });\n const moduleCount = code.modules.size;\n const viewBoxSize = moduleCount + safeMargin * 2;\n const modules: ReactNode[] = [];\n\n for (let row = 0; row < moduleCount; row += 1) {\n for (let column = 0; column < moduleCount; column += 1) {\n if (code.modules.get(row, column) && !isFinderCell(row, column, moduleCount)) {\n modules.push(\n <circle\n cx={safeMargin + column + 0.5}\n cy={safeMargin + row + 0.5}\n data-slot=\"qr-code-dot\"\n fill={foreground}\n key={`${row}-${column}`}\n r=\"0.43\"\n />,\n );\n }\n }\n }\n\n return (\n <svg\n {...props}\n ref={ref}\n aria-label={label}\n className={cx(qrCode(), className)}\n data-dot-shape=\"circle\"\n data-eye-shape=\"rounded-square\"\n data-jaci-component=\"qr-code\"\n data-slot=\"qr-code\"\n height={safeSize}\n role=\"img\"\n style={style}\n viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}\n width={safeSize}\n >\n <title>{label}</title>\n {background !== \"transparent\" ? (\n <rect fill={background} height={viewBoxSize} width={viewBoxSize} x=\"0\" y=\"0\" />\n ) : null}\n {modules}\n <Finder background={finderBackground} color={foreground} x={safeMargin} y={safeMargin} />\n <Finder\n background={finderBackground}\n color={foreground}\n x={safeMargin + moduleCount - 7}\n y={safeMargin}\n />\n <Finder\n background={finderBackground}\n color={foreground}\n x={safeMargin}\n y={safeMargin + moduleCount - 7}\n />\n </svg>\n );\n } catch {\n return (\n <span\n aria-label={label}\n className={cx(qrCode(), className)}\n data-jaci-component=\"qr-code\"\n data-slot=\"qr-code\"\n data-status=\"error\"\n role=\"img\"\n >\n {fallback ?? \"Unable to generate QR code\"}\n </span>\n );\n }\n});\n"],"mappings":";;;;;;AAoBA,SAAS,aAAa,KAAa,QAAgB,MAAc;CAC/D,OACG,MAAM,KAAK,SAAS,KAAO,MAAM,KAAK,UAAU,OAAO,KAAO,OAAO,OAAO,KAAK,SAAS;AAE/F;AAEA,SAAS,OAAO,EACd,GACA,GACA,OACA,cAMC;CACD,OACE,qBAAC,KAAD;EAAG,aAAU;YAAb;GACE,oBAAC,QAAD;IAAM,MAAM;IAAO,QAAO;IAAI,IAAG;IAAI,OAAM;IAAO;IAAM;GAAI,CAAA;GAC5D,oBAAC,QAAD;IAAM,MAAM;IAAY,QAAO;IAAI,IAAG;IAAO,OAAM;IAAI,GAAG,IAAI;IAAG,GAAG,IAAI;GAAI,CAAA;GAC5E,oBAAC,QAAD;IAAM,MAAM;IAAO,QAAO;IAAI,IAAG;IAAM,OAAM;IAAI,GAAG,IAAI;IAAG,GAAG,IAAI;GAAI,CAAA;EACrE;;AAEP;AAEA,MAAa,SAAS,WAAuC,SAAS,OACpE,EACE,aAAa,eACb,WACA,uBAAuB,KACvB,UACA,aAAa,gBACb,QAAQ,WACR,SAAS,GACT,OAAO,KACP,OACA,OACA,GAAG,SAEL,KACA;CACA,MAAM,WAAW,OAAO,SAAS,IAAI,KAAK,OAAO,IAAI,OAAO;CAC5D,MAAM,aAAa,OAAO,SAAS,MAAM,KAAK,UAAU,IAAI,KAAK,MAAM,MAAM,IAAI;CAIjF,MAAM,mBAAmB,eAAe,gBAAgB,UAAU;CAElE,IAAI;EACF,MAAM,OAAO,cAAc,OAAO,OAAO,EAAE,qBAAqB,CAAC;EACjE,MAAM,cAAc,KAAK,QAAQ;EACjC,MAAM,cAAc,cAAc,aAAa;EAC/C,MAAM,UAAuB,CAAC;EAE9B,KAAK,IAAI,MAAM,GAAG,MAAM,aAAa,OAAO,GAC1C,KAAK,IAAI,SAAS,GAAG,SAAS,aAAa,UAAU,GACnD,IAAI,KAAK,QAAQ,IAAI,KAAK,MAAM,KAAK,CAAC,aAAa,KAAK,QAAQ,WAAW,GACzE,QAAQ,KACN,oBAAC,UAAD;GACE,IAAI,aAAa,SAAS;GAC1B,IAAI,aAAa,MAAM;GACvB,aAAU;GACV,MAAM;GAEN,GAAE;EACH,GAFM,GAAG,IAAI,GAAG,QAEhB,CACH;EAKN,OACE,qBAAC,OAAD;GACE,GAAI;GACC;GACL,cAAY;GACZ,WAAW,GAAG,OAAO,GAAG,SAAS;GACjC,kBAAe;GACf,kBAAe;GACf,uBAAoB;GACpB,aAAU;GACV,QAAQ;GACR,MAAK;GACE;GACP,SAAS,OAAO,YAAY,GAAG;GAC/B,OAAO;aAbT;IAeE,oBAAC,SAAD,EAAA,UAAQ,MAAa,CAAA;IACpB,eAAe,gBACd,oBAAC,QAAD;KAAM,MAAM;KAAY,QAAQ;KAAa,OAAO;KAAa,GAAE;KAAI,GAAE;IAAK,CAAA,IAC5E;IACH;IACD,oBAAC,QAAD;KAAQ,YAAY;KAAkB,OAAO;KAAY,GAAG;KAAY,GAAG;IAAa,CAAA;IACxF,oBAAC,QAAD;KACE,YAAY;KACZ,OAAO;KACP,GAAG,aAAa,cAAc;KAC9B,GAAG;IACJ,CAAA;IACD,oBAAC,QAAD;KACE,YAAY;KACZ,OAAO;KACP,GAAG;KACH,GAAG,aAAa,cAAc;IAC/B,CAAA;GACE;;CAET,QAAQ;EACN,OACE,oBAAC,QAAD;GACE,cAAY;GACZ,WAAW,GAAG,OAAO,GAAG,SAAS;GACjC,uBAAoB;GACpB,aAAU;GACV,eAAY;GACZ,MAAK;aAEJ,YAAY;EACT,CAAA;CAEV;AACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"qr-code.js","names":[],"sources":["../../../src/components/qr-code/qr-code.tsx"],"sourcesContent":["import * as QRCodeEncoder from \"qrcode\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { cx } from \"../../styled-system/css\";\nimport { qrCode } from \"../../styled-system/recipes\";\n\nexport type QRCodeErrorCorrectionLevel = \"L\" | \"M\" | \"Q\" | \"H\";\n\nexport interface QRCodeProps\n extends Omit<ComponentPropsWithoutRef<\"svg\">, \"children\" | \"download\"> {\n value: string;\n size?: number;\n margin?: number;\n errorCorrectionLevel?: QRCodeErrorCorrectionLevel;\n foreground?: string;\n background?: string;\n label?: string;\n fallback?: ReactNode;\n /** Enables a native SVG download link inside the rendered code. */\n download?: boolean | string;\n downloadLabel?: string;\n}\n\nfunction isFinderCell(row: number, column: number, size: number) {\n return (\n (row < 7 && column < 7) || (row < 7 && column >= size - 7) || (row >= size - 7 && column < 7)\n );\n}\n\nfunction Finder({\n x,\n y,\n color,\n background,\n}: {\n x: number;\n y: number;\n color: string;\n background: string;\n}) {\n return (\n <g data-slot=\"qr-code-eye\">\n <rect data-slot=\"qr-code-eye-frame\" fill={color} height=\"7\" rx=\"1\" width=\"7\" x={x} y={y} />\n <rect\n data-slot=\"qr-code-eye-cutout\"\n fill={background}\n height=\"5\"\n rx=\"0.75\"\n width=\"5\"\n x={x + 1}\n y={y + 1}\n />\n <rect\n data-slot=\"qr-code-eyeball\"\n fill={color}\n height=\"3\"\n rx=\"0.5\"\n width=\"3\"\n x={x + 2}\n y={y + 2}\n />\n </g>\n );\n}\n\nfunction escapeXml(value: string) {\n return value.replace(/[&<>'\"]/g, (character) => {\n const entities: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n \"'\": \"'\",\n '\"': \""\",\n };\n return entities[character] ?? character;\n });\n}\n\nfunction createDownloadSvg({\n background,\n dots,\n foreground,\n finderBackground,\n label,\n margin,\n moduleCount,\n}: {\n background: string;\n dots: readonly [number, number][];\n foreground: string;\n finderBackground: string;\n label: string;\n margin: number;\n moduleCount: number;\n}) {\n const viewBoxSize = moduleCount + margin * 2;\n const backgroundMarkup =\n background === \"transparent\"\n ? \"\"\n : `<rect fill=\"${escapeXml(background)}\" height=\"${viewBoxSize}\" width=\"${viewBoxSize}\" x=\"0\" y=\"0\"/>`;\n const dotsMarkup = dots\n .map(\n ([row, column]) =>\n `<circle cx=\"${margin + column + 0.5}\" cy=\"${margin + row + 0.5}\" fill=\"${escapeXml(foreground)}\" r=\"0.43\"/>`,\n )\n .join(\"\");\n const finderMarkup = (x: number, y: number) =>\n `<g><rect fill=\"${escapeXml(foreground)}\" height=\"7\" rx=\"1\" width=\"7\" x=\"${x}\" y=\"${y}\"/><rect fill=\"${escapeXml(finderBackground)}\" height=\"5\" rx=\"0.75\" width=\"5\" x=\"${x + 1}\" y=\"${y + 1}\"/><rect fill=\"${escapeXml(foreground)}\" height=\"3\" rx=\"0.5\" width=\"3\" x=\"${x + 2}\" y=\"${y + 2}\"/></g>`;\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" aria-label=\"${escapeXml(label)}\" role=\"img\" viewBox=\"0 0 ${viewBoxSize} ${viewBoxSize}\">${backgroundMarkup}${dotsMarkup}${finderMarkup(margin, margin)}${finderMarkup(margin + moduleCount - 7, margin)}${finderMarkup(margin, margin + moduleCount - 7)}</svg>`;\n}\n\nexport const QRCode = forwardRef<SVGSVGElement, QRCodeProps>(function QRCode(\n {\n // A QR code needs a deterministic high-contrast base. Inheriting\n // `currentColor` or a transparent surface can make finder layers merge\n // in dark scopes, so the defaults intentionally remain black on white.\n background = \"#ffffff\",\n className,\n download = false,\n downloadLabel = \"Download QR code\",\n errorCorrectionLevel = \"Q\",\n fallback,\n foreground = \"#18181b\",\n label = \"QR code\",\n margin = 2,\n size = 192,\n style,\n value,\n ...props\n },\n ref,\n) {\n const safeSize = Number.isFinite(size) && size > 0 ? size : 192;\n const safeMargin = Number.isFinite(margin) && margin >= 0 ? Math.floor(margin) : 2;\n const finderBackground =\n background === \"transparent\" ? \"var(--jaci-colors-surface-raised)\" : background;\n\n try {\n const code = QRCodeEncoder.create(value, { errorCorrectionLevel });\n const moduleCount = code.modules.size;\n const viewBoxSize = moduleCount + safeMargin * 2;\n const modules: ReactNode[] = [];\n const dotCoordinates: [number, number][] = [];\n\n for (let row = 0; row < moduleCount; row += 1) {\n for (let column = 0; column < moduleCount; column += 1) {\n if (code.modules.get(row, column) && !isFinderCell(row, column, moduleCount)) {\n dotCoordinates.push([row, column]);\n modules.push(\n <circle\n cx={safeMargin + column + 0.5}\n cy={safeMargin + row + 0.5}\n data-slot=\"qr-code-dot\"\n fill={foreground}\n key={`${row}-${column}`}\n r=\"0.43\"\n />,\n );\n }\n }\n }\n\n const downloadHref =\n download &&\n `data:image/svg+xml;charset=utf-8,${encodeURIComponent(\n createDownloadSvg({\n background,\n dots: dotCoordinates,\n foreground,\n finderBackground: background === \"transparent\" ? \"#ffffff\" : background,\n label,\n margin: safeMargin,\n moduleCount,\n }),\n )}`;\n const downloadFilename = typeof download === \"string\" ? download : \"qrcode.svg\";\n const visualCode = (\n <>\n {background !== \"transparent\" ? (\n <rect fill={background} height={viewBoxSize} width={viewBoxSize} x=\"0\" y=\"0\" />\n ) : null}\n {modules}\n <Finder background={finderBackground} color={foreground} x={safeMargin} y={safeMargin} />\n <Finder\n background={finderBackground}\n color={foreground}\n x={safeMargin + moduleCount - 7}\n y={safeMargin}\n />\n <Finder\n background={finderBackground}\n color={foreground}\n x={safeMargin}\n y={safeMargin + moduleCount - 7}\n />\n </>\n );\n\n const svg = (\n <svg\n {...props}\n ref={ref}\n aria-hidden={downloadHref ? true : undefined}\n aria-label={downloadHref ? undefined : label}\n className={cx(qrCode(), className)}\n data-dot-shape=\"circle\"\n data-download={download ? \"true\" : undefined}\n data-eye-shape=\"rounded-square\"\n data-jaci-component=\"qr-code\"\n data-slot=\"qr-code\"\n height={safeSize}\n role={downloadHref ? undefined : \"img\"}\n style={style}\n viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}\n width={safeSize}\n >\n <title>{label}</title>\n {visualCode}\n </svg>\n );\n\n return downloadHref ? (\n <a\n aria-label={downloadLabel}\n data-jaci-component=\"qr-code-download\"\n data-slot=\"qr-code-download\"\n download={downloadFilename}\n href={downloadHref}\n >\n {svg}\n </a>\n ) : (\n svg\n );\n } catch {\n return (\n <span\n aria-label={label}\n className={cx(qrCode(), className)}\n data-jaci-component=\"qr-code\"\n data-slot=\"qr-code\"\n data-status=\"error\"\n role=\"img\"\n >\n {fallback ?? \"Unable to generate QR code\"}\n </span>\n );\n }\n});\n"],"mappings":"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"}
|
package/dist/styles.css
CHANGED
|
@@ -10872,12 +10872,12 @@
|
|
|
10872
10872
|
|
|
10873
10873
|
@layer utilities{
|
|
10874
10874
|
|
|
10875
|
-
.jaci-
|
|
10876
|
-
background: var(--jaci-colors-
|
|
10875
|
+
.jaci-bg_var\(--jaci-colors-surface-raised\) {
|
|
10876
|
+
background: var(--jaci-colors-surface-raised);
|
|
10877
10877
|
}
|
|
10878
10878
|
|
|
10879
|
-
.jaci-
|
|
10880
|
-
background:
|
|
10879
|
+
.jaci-bg_\#ffffff {
|
|
10880
|
+
background: #ffffff;
|
|
10881
10881
|
}
|
|
10882
10882
|
|
|
10883
10883
|
.jaci-gap_8px {
|
|
@@ -10896,8 +10896,8 @@
|
|
|
10896
10896
|
page: 1px;
|
|
10897
10897
|
}
|
|
10898
10898
|
|
|
10899
|
-
.jaci-
|
|
10900
|
-
color:
|
|
10899
|
+
.jaci-c_\#18181b {
|
|
10900
|
+
color: #18181b;
|
|
10901
10901
|
}
|
|
10902
10902
|
|
|
10903
10903
|
.jaci-translate-x_2 {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jaci-ui",
|
|
3
3
|
"description": "Accessible, themeable React components by Jaci UI",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Richard Borges",
|
|
@@ -86,13 +86,13 @@
|
|
|
86
86
|
"access": "public"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@pandacss/dev": "^1.11.
|
|
89
|
+
"@pandacss/dev": "^1.11.5",
|
|
90
90
|
"@types/qrcode": "^1.5.6",
|
|
91
|
-
"@types/react": "^19.2.
|
|
92
|
-
"@types/react-dom": "^19.2.
|
|
91
|
+
"@types/react": "^19.2.18",
|
|
92
|
+
"@types/react-dom": "^19.2.4",
|
|
93
93
|
"jsdom": "^27.4.0",
|
|
94
|
-
"react": "^19.2.
|
|
95
|
-
"react-dom": "^19.2.
|
|
94
|
+
"react": "^19.2.8",
|
|
95
|
+
"react-dom": "^19.2.8",
|
|
96
96
|
"tsdown": "^0.22.4"
|
|
97
97
|
},
|
|
98
98
|
"scripts": {
|