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 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
- ### Mídia e utilitários visuais
87
+ ### Media and visual utilities
88
88
 
89
- `Carousel` oferece slides acessíveis com navegação por teclado, indicadores, swipe e autoplay
90
- opcional. Sempre forneça um `aria-label` no root e texto alternativo nas imagens:
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` gera SVG no servidor e no cliente, com módulos circulares e olhos quadrados
112
- arredondados. O valor pode ser controlado diretamente pela aplicação:
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
- Para downloads, `DownloadTrigger` é um link HTML comum e não faz fetch nem cria `Blob`:
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
- Em URLs cross-origin, o nome e a própria autorização do download continuam sujeitos às regras
132
- do navegador e aos headers do servidor.
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` para uma linha semântica ou decorativa entre seções e `Spacer` quando precisar
135
- apenas de espaço, sem linha:
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
- Todos esses componentes continuam compatíveis com SSR e React 18/19. `Carousel` é o único novo
143
- módulo interativo; os demais não acessam APIs do navegador durante importação ou renderização.
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: disabled || loading ? void 0 : renderedProps.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 { ComponentPropsWithoutRef, MouseEventHandler, ReactElement, ReactNode } 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 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 const renderedProps = render.props as {\n className?: string;\n children?: ReactNode;\n onClick?: MouseEventHandler<HTMLElement>;\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: disabled || loading ? undefined : renderedProps.onClick,\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 ref={ref}\n type={type}\n >\n {childrenWithIcons}\n </button>\n );\n});\n"],"mappings":";;;;;;;AA2BA,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,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;EACV,MAAM,gBAAgB,OAAO;EAM7B,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,YAAY,UAAU,KAAA,IAAY,cAAc;EAC3D,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;EACjB;EACC;YAEL;CACK,CAAA;AAEZ,CAAC"}
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: disabled || loading ? void 0 : renderedProps.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 { ComponentPropsWithoutRef, MouseEventHandler, ReactElement, ReactNode } 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 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 const renderedProps = render.props as {\n className?: string;\n children?: ReactNode;\n onClick?: MouseEventHandler<HTMLElement>;\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: disabled || loading ? undefined : renderedProps.onClick,\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 ref={ref}\n type={type}\n >\n {childrenWithIcons}\n </button>\n );\n});\n"],"mappings":";;;;;;;AA2BA,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,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;EACV,MAAM,gBAAgB,OAAO;EAM7B,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,YAAY,UAAU,KAAA,IAAY,cAAc;EAC3D,CAAC;CACH;CAEA,OACE,oBAAC,UAAD;EACE,GAAI;EACJ,aAAW,WAAW,KAAA;EACtB,WAAW;EACX,uBAAoB;EACpB,aAAU;EACV,UAAU,YAAY;EACjB;EACC;YAEL;CACK,CAAA;AAEZ,CAAC"}
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
- const QRCode = (0, react.forwardRef)(function QRCode({ background = "transparent", className, errorCorrectionLevel = "Q", fallback, foreground = "currentColor", label = "QR code", margin = 2, size = 192, style, value, ...props }, ref) {
46
+ function escapeXml(value) {
47
+ return value.replace(/[&<>'"]/g, (character) => {
48
+ return {
49
+ "&": "&amp;",
50
+ "<": "&lt;",
51
+ ">": "&gt;",
52
+ "'": "&apos;",
53
+ "\"": "&quot;"
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" ? "white" : background;
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
- 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)) modules.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
53
- cx: safeMargin + column + .5,
54
- cy: safeMargin + row + .5,
55
- "data-slot": "qr-code-dot",
56
- fill: foreground,
57
- r: "0.43"
58
- }, `${row}-${column}`));
59
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
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-label": label,
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":";;;;;;;;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,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;EAAG,aAAU;YAAb;GACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IAAM,MAAM;IAAO,QAAO;IAAI,IAAG;IAAI,OAAM;IAAO;IAAM;GAAI,CAAA;GAC5D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IAAM,MAAM;IAAY,QAAO;IAAI,IAAG;IAAO,OAAM;IAAI,GAAG,IAAI;IAAG,GAAG,IAAI;GAAI,CAAA;GAC5E,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IAAM,MAAM;IAAO,QAAO;IAAI,IAAG;IAAM,OAAM;IAAI,GAAG,IAAI;IAAG,GAAG,IAAI;GAAI,CAAA;EACrE;;AAEP;AAEA,MAAa,UAAA,GAAA,MAAA,WAAA,CAAgD,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,OAAOA,OAAc,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,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACE,IAAI,aAAa,SAAS;GAC1B,IAAI,aAAa,MAAM;GACvB,aAAU;GACV,MAAM;GAEN,GAAE;EACH,GAFM,GAAG,IAAI,GAAG,QAEhB,CACH;EAKN,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GACE,GAAI;GACC;GACL,cAAY;GACZ,WAAWC,WAAAA,GAAGC,gBAAAA,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,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD,EAAA,UAAQ,MAAa,CAAA;IACpB,eAAe,gBACd,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,MAAM;KAAY,QAAQ;KAAa,OAAO;KAAa,GAAE;KAAI,GAAE;IAAK,CAAA,IAC5E;IACH;IACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAQ,YAAY;KAAkB,OAAO;KAAY,GAAG;KAAY,GAAG;IAAa,CAAA;IACxF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KACE,YAAY;KACZ,OAAO;KACP,GAAG,aAAa,cAAc;KAC9B,GAAG;IACJ,CAAA;IACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KACE,YAAY;KACZ,OAAO;KACP,GAAG;KACH,GAAG,aAAa,cAAc;IAC/B,CAAA;GACE;;CAET,QAAQ;EACN,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GACE,cAAY;GACZ,WAAWD,WAAAA,GAAGC,gBAAAA,OAAO,GAAG,SAAS;GACjC,uBAAoB;GACpB,aAAU;GACV,eAAY;GACZ,MAAK;aAEJ,YAAY;EACT,CAAA;CAEV;AACF,CAAC"}
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 \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n \"'\": \"&apos;\",\n '\"': \"&quot;\",\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
- const QRCode = forwardRef(function QRCode({ background = "transparent", className, errorCorrectionLevel = "Q", fallback, foreground = "currentColor", label = "QR code", margin = 2, size = 192, style, value, ...props }, ref) {
44
+ function escapeXml(value) {
45
+ return value.replace(/[&<>'"]/g, (character) => {
46
+ return {
47
+ "&": "&amp;",
48
+ "<": "&lt;",
49
+ ">": "&gt;",
50
+ "'": "&apos;",
51
+ "\"": "&quot;"
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" ? "white" : background;
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
- 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)) modules.push(/* @__PURE__ */ jsx("circle", {
51
- cx: safeMargin + column + .5,
52
- cy: safeMargin + row + .5,
53
- "data-slot": "qr-code-dot",
54
- fill: foreground,
55
- r: "0.43"
56
- }, `${row}-${column}`));
57
- return /* @__PURE__ */ jsxs("svg", {
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-label": label,
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 \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n \"'\": \"&apos;\",\n '\"': \"&quot;\",\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":";;;;;;AAwBA,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,aAAU;IAAoB,MAAM;IAAO,QAAO;IAAI,IAAG;IAAI,OAAM;IAAO;IAAM;GAAI,CAAA;GAC1F,oBAAC,QAAD;IACE,aAAU;IACV,MAAM;IACN,QAAO;IACP,IAAG;IACH,OAAM;IACN,GAAG,IAAI;IACP,GAAG,IAAI;GACR,CAAA;GACD,oBAAC,QAAD;IACE,aAAU;IACV,MAAM;IACN,QAAO;IACP,IAAG;IACH,OAAM;IACN,GAAG,IAAI;IACP,GAAG,IAAI;GACR,CAAA;EACA;;AAEP;AAEA,SAAS,UAAU,OAAe;CAChC,OAAO,MAAM,QAAQ,aAAa,cAAc;EAQ9C,OAAO;GANL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,MAAK;EAEO,EAAE,cAAc;CAChC,CAAC;AACH;AAEA,SAAS,kBAAkB,EACzB,YACA,MACA,YACA,kBACA,OACA,QACA,eASC;CACD,MAAM,cAAc,cAAc,SAAS;CAC3C,MAAM,mBACJ,eAAe,gBACX,KACA,eAAe,UAAU,UAAU,EAAE,YAAY,YAAY,WAAW,YAAY;CAC1F,MAAM,aAAa,KAChB,KACE,CAAC,KAAK,YACL,eAAe,SAAS,SAAS,GAAI,QAAQ,SAAS,MAAM,GAAI,UAAU,UAAU,UAAU,EAAE,aACpG,CAAC,CACA,KAAK,EAAE;CACV,MAAM,gBAAgB,GAAW,MAC/B,kBAAkB,UAAU,UAAU,EAAE,mCAAmC,EAAE,OAAO,EAAE,iBAAiB,UAAU,gBAAgB,EAAE,sCAAsC,IAAI,EAAE,OAAO,IAAI,EAAE,iBAAiB,UAAU,UAAU,EAAE,qCAAqC,IAAI,EAAE,OAAO,IAAI,EAAE;CAE7R,OAAO,uDAAuD,UAAU,KAAK,EAAE,4BAA4B,YAAY,GAAG,YAAY,IAAI,mBAAmB,aAAa,aAAa,QAAQ,MAAM,IAAI,aAAa,SAAS,cAAc,GAAG,MAAM,IAAI,aAAa,QAAQ,SAAS,cAAc,CAAC,EAAE;AAC3S;AAEA,MAAa,SAAS,WAAuC,SAAS,OACpE,EAIE,aAAa,WACb,WACA,WAAW,OACX,gBAAgB,oBAChB,uBAAuB,KACvB,UACA,aAAa,WACb,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;CACjF,MAAM,mBACJ,eAAe,gBAAgB,sCAAsC;CAEvE,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;EAC9B,MAAM,iBAAqC,CAAC;EAE5C,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,GAAG;GAC5E,eAAe,KAAK,CAAC,KAAK,MAAM,CAAC;GACjC,QAAQ,KACN,oBAAC,UAAD;IACE,IAAI,aAAa,SAAS;IAC1B,IAAI,aAAa,MAAM;IACvB,aAAU;IACV,MAAM;IAEN,GAAE;GACH,GAFM,GAAG,IAAI,GAAG,QAEhB,CACH;EACF;EAIJ,MAAM,eACJ,YACA,oCAAoC,mBAClC,kBAAkB;GAChB;GACA,MAAM;GACN;GACA,kBAAkB,eAAe,gBAAgB,YAAY;GAC7D;GACA,QAAQ;GACR;EACF,CAAC,CACH;EACF,MAAM,mBAAmB,OAAO,aAAa,WAAW,WAAW;EACnE,MAAM,aACJ,qBAAA,UAAA,EAAA,UAAA;GACG,eAAe,gBACd,oBAAC,QAAD;IAAM,MAAM;IAAY,QAAQ;IAAa,OAAO;IAAa,GAAE;IAAI,GAAE;GAAK,CAAA,IAC5E;GACH;GACD,oBAAC,QAAD;IAAQ,YAAY;IAAkB,OAAO;IAAY,GAAG;IAAY,GAAG;GAAa,CAAA;GACxF,oBAAC,QAAD;IACE,YAAY;IACZ,OAAO;IACP,GAAG,aAAa,cAAc;IAC9B,GAAG;GACJ,CAAA;GACD,oBAAC,QAAD;IACE,YAAY;IACZ,OAAO;IACP,GAAG;IACH,GAAG,aAAa,cAAc;GAC/B,CAAA;EACD,EAAA,CAAA;EAGJ,MAAM,MACJ,qBAAC,OAAD;GACE,GAAI;GACC;GACL,eAAa,eAAe,OAAO,KAAA;GACnC,cAAY,eAAe,KAAA,IAAY;GACvC,WAAW,GAAG,OAAO,GAAG,SAAS;GACjC,kBAAe;GACf,iBAAe,WAAW,SAAS,KAAA;GACnC,kBAAe;GACf,uBAAoB;GACpB,aAAU;GACV,QAAQ;GACR,MAAM,eAAe,KAAA,IAAY;GAC1B;GACP,SAAS,OAAO,YAAY,GAAG;GAC/B,OAAO;aAfT,CAiBE,oBAAC,SAAD,EAAA,UAAQ,MAAa,CAAA,GACpB,UACE;;EAGP,OAAO,eACL,oBAAC,KAAD;GACE,cAAY;GACZ,uBAAoB;GACpB,aAAU;GACV,UAAU;GACV,MAAM;aAEL;EACA,CAAA,IAEH;CAEJ,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"}
package/dist/styles.css CHANGED
@@ -10872,12 +10872,12 @@
10872
10872
 
10873
10873
  @layer utilities{
10874
10874
 
10875
- .jaci-bg_white {
10876
- background: var(--jaci-colors-white);
10875
+ .jaci-bg_var\(--jaci-colors-surface-raised\) {
10876
+ background: var(--jaci-colors-surface-raised);
10877
10877
  }
10878
10878
 
10879
- .jaci-bg_transparent {
10880
- background: var(--jaci-colors-transparent);
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-c_currentColor {
10900
- color: currentColor;
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.1",
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.4",
89
+ "@pandacss/dev": "^1.11.5",
90
90
  "@types/qrcode": "^1.5.6",
91
- "@types/react": "^19.2.17",
92
- "@types/react-dom": "^19.2.3",
91
+ "@types/react": "^19.2.18",
92
+ "@types/react-dom": "^19.2.4",
93
93
  "jsdom": "^27.4.0",
94
- "react": "^19.2.7",
95
- "react-dom": "^19.2.7",
94
+ "react": "^19.2.8",
95
+ "react-dom": "^19.2.8",
96
96
  "tsdown": "^0.22.4"
97
97
  },
98
98
  "scripts": {