@liquid-js/qr-code-styling 5.0.0-1 → 5.0.0-3
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/README.md +38 -0
- package/lib/border-plugin.js +2 -0
- package/lib/border-plugin.js.map +1 -0
- package/lib/core/qr-code-styling.d.ts +5 -2
- package/lib/core/qr-svg.d.ts +2 -2
- package/lib/figures/corner-dot.d.ts +2 -1
- package/lib/figures/corner-square.d.ts +2 -1
- package/lib/figures/dot.d.ts +3 -2
- package/lib/figures/square-elements.d.ts +0 -1
- package/lib/index.d.ts +1 -1
- package/lib/node.d.ts +1 -1
- package/lib/plugin-utils.js +2 -0
- package/lib/plugin-utils.js.map +1 -0
- package/lib/plugins/border.d.ts +38 -0
- package/lib/plugins/utils.d.ts +2 -0
- package/lib/qr-code-styling-node.js +476 -413
- package/lib/qr-code-styling-node.js.map +1 -1
- package/lib/qr-code-styling.js +1 -1
- package/lib/qr-code-styling.js.map +1 -1
- package/lib/utils/options.d.ts +26 -0
- package/lib/utils/svg.d.ts +7 -1
- package/package.json +12 -2
package/README.md
CHANGED
|
@@ -125,6 +125,44 @@ const buffer = await new Promise((resolve) => {
|
|
|
125
125
|
await writeFile('qr.pdf', buffer)
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
+
### Plugins <img align="right" src="https://raw.githubusercontent.com/Liquid-JS/qr-code-styling/master/src/assets/border.png" width="240" />
|
|
129
|
+
|
|
130
|
+
Version `5.0.0` of the library introduces plugin support, enabling you to further customize the shape of dots and corners. Additionally, plugins can apply effects, such as adding borders, to enhance the final QR code output.
|
|
131
|
+
|
|
132
|
+
#### Plugin development
|
|
133
|
+
|
|
134
|
+
A simple plugin example to customize QR code dots:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { svgPath, DrawArgs } from '@liquid-js/qr-code-styling/plugin-utils'
|
|
138
|
+
|
|
139
|
+
const qrCode = new QRCodeStyling({
|
|
140
|
+
plugins: [
|
|
141
|
+
{
|
|
142
|
+
drawDot: (args: DrawArgs): SVGElement | undefined => {
|
|
143
|
+
const { size, x, y, document } = args
|
|
144
|
+
|
|
145
|
+
const element = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
|
146
|
+
// Insert your own SVG path definition, or implement neighbour-aware logic through args.getNeighbor()
|
|
147
|
+
element.setAttribute(
|
|
148
|
+
'd',
|
|
149
|
+
svgPath`M ${x} ${y + (size - size) / 2}
|
|
150
|
+
v ${size}
|
|
151
|
+
h ${size / 2}
|
|
152
|
+
a ${size / 2} ${size / 2} 0 0 0 0 ${-size}
|
|
153
|
+
z`
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return element
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
]
|
|
160
|
+
// ...other options
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
See [Border plugin](https://github.com/Liquid-JS/qr-code-styling/blob/master/src/plugins/border.ts) and [figures](https://github.com/Liquid-JS/qr-code-styling/tree/master/src/figures) for further reference.
|
|
165
|
+
|
|
128
166
|
### Kanji support
|
|
129
167
|
|
|
130
168
|
For Kanji mode to work, import `stringToBytesFuncs` from `@liquid-js/qr-code-styling/kanji` and inclue it with config.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let t=/\.?0+$/;function e(e){return"string"==typeof e?e:e.toFixed(7).replace(t,"")}function i(t,...i){return t.reduce((t,r,n)=>{let s="";return n&&(s=i[n-1]),"number"==typeof s&&(s=e(s)),`${t}${s}${r}`},"").trim().replace(/[\s\n\r]+/gim," ")}var r,n=r||={};n.top="top",n.bottom="bottom",n.left="left",n.right="right";export var BorderPlugin=class{pluginOptions;id;constructor(t,e=Math.random().toFixed(10).substring(2)){this.pluginOptions=t,this.id=e}postProcess(t,n){let{document:s}=n,o=this.pluginOptions.size+(this.pluginOptions.margin||0)+(this.pluginOptions.innerBorder?.size||0)+(this.pluginOptions.innerBorder?.margin||0)+(this.pluginOptions.outerBorder?.size||0)+(this.pluginOptions.outerBorder?.margin||0),$=function(t,i){t.setAttribute("width",e(parseFloat(t.getAttribute("width")||"0")+2*i)),t.setAttribute("height",e(parseFloat(t.getAttribute("height")||"0")+2*i));let r=(t.getAttribute("viewBox")||"").split(" ").map((t,e)=>parseFloat(t)+(e<2?-1:2)*i);if(t.setAttribute("viewBox",r.map(e).join(" ")),!(r.length<4))return{left:r[0],right:r[2]+r[0],top:r[1],bottom:r[3]+r[1]}}(t,o);if($){var p=($.left+$.right)/2,h=($.top+$.bottom)/2,a=Math.min(n.width,n.height)/2*(1-(this.pluginOptions.round||0)),l=Math.min($.right-$.left-2*o,$.bottom-$.top-2*o)/2-a;n=i=>{const r=i.size,n=l+=(i.margin||0)+r/2,o=this.pluginOptions.round?l:0,$=this.pluginOptions.round?a:a+l;l+=r/2;const u=s.createElementNS("http://www.w3.org/2000/svg","rect");return u.setAttribute("width",e(2*($+o))),u.setAttribute("height",e(2*($+o))),u.setAttribute("x",e(p-$-o)),u.setAttribute("y",e(h-$-o)),u.setAttribute("rx",e(o)),u.setAttribute("fill","none"),u.setAttribute("stroke",i.color),u.setAttribute("stroke-width",e(r)),i.dasharray&&u.setAttribute("stroke-dasharray",i.dasharray),t.appendChild(u),n},this.pluginOptions.innerBorder&&n(this.pluginOptions.innerBorder);var u=n(this.pluginOptions);this.pluginOptions.outerBorder&&n(this.pluginOptions.outerBorder),[r.left,r.top,r.right,r.bottom].forEach(n=>{var o=this.pluginOptions.text[n];if(o){let g=Array.from(t.childNodes).find(t=>"DEFS"==t.tagName.toUpperCase());g||(g=s.createElementNS("http://www.w3.org/2000/svg","defs"),t.appendChild(g));let d=s.createElementNS("http://www.w3.org/2000/svg","path");var $=o.size||this.pluginOptions.text.size||1,l=this.pluginOptions.round?u-$/3:0;let b=this.pluginOptions.round?a:a+(u-$/3);switch(n){case r.top:d.setAttribute("d",i`M ${p} ${h+l+b} h ${-b} a ${l} ${l} 0 0 1 ${-l} ${-l} v ${-2*b} a ${l} ${l} 0 0 1 ${l} ${-l} h ${2*b} a ${l} ${l} 0 0 1 ${l} ${l} v ${2*b} a ${l} ${l} 0 0 1 ${-l} ${l} h ${-b}`);break;case r.bottom:this.pluginOptions.round?l+=2*$/3:b+=2*$/3,d.setAttribute("d",i`M ${p} ${h-l-b} h ${-b} a ${l} ${l} 0 0 0 ${-l} ${l} v ${2*b} a ${l} ${l} 0 0 0 ${l} ${l} h ${2*b} a ${l} ${l} 0 0 0 ${l} ${-l} v ${-2*b} a ${l} ${l} 0 0 0 ${-l} ${-l} h ${-b}`);break;case r.left:d.setAttribute("d",i`M ${p+l+b} ${h} v ${b} a ${l} ${l} 0 0 1 ${-l} ${l} h ${-2*b} a ${l} ${l} 0 0 1 ${-l} ${-l} v ${-2*b} a ${l} ${l} 0 0 1 ${l} ${-l} h ${2*b} a ${l} ${l} 0 0 1 ${l} ${l} v ${b}`);break;case r.right:d.setAttribute("d",i`M ${p-l-b} ${h} v ${-b} a ${l} ${l} 0 0 1 ${l} ${-l} h ${2*b} a ${l} ${l} 0 0 1 ${l} ${l} v ${2*b} a ${l} ${l} 0 0 1 ${-l} ${l} h ${-2*b} a ${l} ${l} 0 0 1 ${-l} ${-l} v ${-b}`)}n=`border-text-${n}-${this.id}`,d.setAttribute("id",n),d.setAttribute("fill","none"),(l=s.createElementNS("http://www.w3.org/2000/svg","tspan")).setAttribute("font-family",o.font||this.pluginOptions.text.font||"sans-serif"),l.setAttribute("fill",o.color||this.pluginOptions.text.color||"#000"),l.setAttribute("font-weight",e(o.fontWeight||this.pluginOptions.text.fontWeight||"normal")),l.setAttribute("font-style",o.fontStyle||this.pluginOptions.text.fontStyle||"normal"),l.setAttribute("font-size",e($)),l.textContent=o.content,(o=s.createElementNS("http://www.w3.org/2000/svg","textPath")).setAttributeNS("http://www.w3.org/1999/xlink","xlink:href","#"+n),o.setAttribute("startOffset","50%"),o.setAttribute("text-anchor","middle"),o.appendChild(l),($=s.createElementNS("http://www.w3.org/2000/svg","text")).appendChild(o),g.appendChild(d),t.appendChild($)}})}}};
|
|
2
|
+
//# sourceMappingURL=border-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"border-plugin.js","sources":["../src/utils/svg.ts","../src/plugins/border.ts"],"sourcesContent":["import { RotateFigureArgs } from '../types/helper.js'\r\n\r\nconst rx = /\\.?0+$/\r\n\r\nexport function numToAttr(value: number | string) {\r\n if (typeof value == 'string') return value\r\n return value.toFixed(7).replace(rx, '')\r\n}\r\n\r\nexport function svgPath(strings: TemplateStringsArray, ...values: unknown[]) {\r\n return strings\r\n .reduce((t, v, i) => {\r\n let p: unknown = ''\r\n if (i) p = values[i - 1]\r\n if (typeof p == 'number') p = numToAttr(p)\r\n return `${t}${p}${v}`\r\n }, '')\r\n .trim()\r\n .replace(/[\\s\\n\\r]+/gim, ' ')\r\n}\r\n\r\nexport function rotateFigure<T extends SVGElement | ReadonlyArray<SVGElement>>({ draw, ...args }: RotateFigureArgs<T>) {\r\n const { x, y, size, rotation = 0 } = args\r\n const cx = x + size / 2\r\n const cy = y + size / 2\r\n\r\n const element = draw(args)\r\n if (rotation) (Array.isArray(element) ? element : [element])\r\n .forEach(el => el.setAttribute('transform', `rotate(${numToAttr((180 * rotation) / Math.PI)},${cx},${cy})`))\r\n return element\r\n}\r\n\r\nexport function scalePath(path: Array<string | number>, { x, y, size }: {\r\n x: number\r\n y: number\r\n size: number\r\n}) {\r\n let move = false\r\n let i = 0\r\n return path\r\n .map((v) => {\r\n if (typeof v == 'string') {\r\n i = 0\r\n move = v.toUpperCase() == v\r\n return v\r\n }\r\n i++\r\n v = v * size\r\n if (move) {\r\n v += i % 2 == 1 ? x : y\r\n }\r\n return numToAttr(v)\r\n })\r\n .join(' ')\r\n}\r\n\r\nexport function extendSVG(svg: SVGSVGElement, padding: number) {\r\n svg.setAttribute('width', numToAttr(parseFloat(svg.getAttribute('width') || '0') + 2 * padding))\r\n svg.setAttribute('height', numToAttr(parseFloat(svg.getAttribute('height') || '0') + 2 * padding))\r\n const vb = (svg.getAttribute('viewBox') || '').split(' ').map((v, i) => parseFloat(v) + (i < 2 ? -1 : 2) * padding)\r\n svg.setAttribute('viewBox', vb.map(numToAttr).join(' '))\r\n if (vb.length < 4)\r\n return undefined\r\n return {\r\n left: vb[0],\r\n right: vb[2] + vb[0],\r\n top: vb[1],\r\n bottom: vb[3] + vb[1]\r\n }\r\n}\r\n","import { Options, Plugin } from '../utils/options.js'\r\nimport { extendSVG, numToAttr, svgPath } from './utils.js'\r\n\r\nenum TextPosition {\r\n top = 'top',\r\n bottom = 'bottom',\r\n left = 'left',\r\n right = 'right'\r\n}\r\n\r\nexport interface BorderConfig {\r\n size: number\r\n color: string\r\n dasharray?: string\r\n margin?: number\r\n}\r\n\r\nexport interface TextConfig {\r\n font?: string\r\n color?: string\r\n size?: number\r\n fontWeight?: 'normal' | 'bold' | 'bolder' | 'lighter' | number\r\n fontStyle?: 'normal' | 'italic' | 'oblique'\r\n}\r\n\r\nexport interface BorderPluginOptions extends BorderConfig {\r\n /** Border roundnes, from 0 (square) to 1 (circle) */\r\n round?: number\r\n text: TextConfig & {\r\n [key in TextPosition]?: TextConfig & {\r\n content: string\r\n }\r\n }\r\n innerBorder?: BorderConfig\r\n outerBorder?: BorderConfig\r\n}\r\n\r\nexport class BorderPlugin implements Plugin {\r\n\r\n constructor(private readonly pluginOptions: BorderPluginOptions, private readonly id = Math.random().toFixed(10).substring(2)) { }\r\n\r\n postProcess(svg: SVGSVGElement, options: Options) {\r\n const { document } = options\r\n const thickness = (\r\n this.pluginOptions.size + (this.pluginOptions.margin || 0)\r\n + (this.pluginOptions.innerBorder?.size || 0) + (this.pluginOptions.innerBorder?.margin || 0)\r\n + (this.pluginOptions.outerBorder?.size || 0) + (this.pluginOptions.outerBorder?.margin || 0)\r\n )\r\n const drawArea = extendSVG(svg, thickness)\r\n if (!drawArea)\r\n return\r\n\r\n const cx = (drawArea.left + drawArea.right) / 2\r\n const cy = (drawArea.top + drawArea.bottom) / 2\r\n const lineSize = Math.min(options.width, options.height) / 2 * (1 - (this.pluginOptions.round || 0))\r\n let r = (Math.min(drawArea.right - drawArea.left - 2 * thickness, drawArea.bottom - drawArea.top - 2 * thickness) / 2) - lineSize\r\n\r\n const drawBorder = (cfg: BorderConfig) => {\r\n const t = cfg.size\r\n const mid = r += (cfg.margin || 0) + t / 2\r\n const pathR = this.pluginOptions.round ? r : 0\r\n const pathL = this.pluginOptions.round ? lineSize : lineSize + r\r\n r += t / 2\r\n\r\n const element = document.createElementNS('http://www.w3.org/2000/svg', 'rect')\r\n element.setAttribute('width', numToAttr((pathL + pathR) * 2))\r\n element.setAttribute('height', numToAttr((pathL + pathR) * 2))\r\n element.setAttribute('x', numToAttr(cx - pathL - pathR))\r\n element.setAttribute('y', numToAttr(cy - pathL - pathR))\r\n element.setAttribute('rx', numToAttr(pathR))\r\n element.setAttribute('fill', 'none')\r\n element.setAttribute('stroke', cfg.color)\r\n element.setAttribute('stroke-width', numToAttr(t))\r\n if (cfg.dasharray) {\r\n element.setAttribute('stroke-dasharray', cfg.dasharray)\r\n }\r\n\r\n svg.appendChild(element)\r\n return mid\r\n }\r\n\r\n if (this.pluginOptions.innerBorder) {\r\n drawBorder(this.pluginOptions.innerBorder)\r\n }\r\n\r\n const textRadius = drawBorder(this.pluginOptions)\r\n\r\n if (this.pluginOptions.outerBorder) {\r\n drawBorder(this.pluginOptions.outerBorder)\r\n }\r\n\r\n [TextPosition.left, TextPosition.top, TextPosition.right, TextPosition.bottom].forEach(postion => {\r\n const config = this.pluginOptions.text[postion]\r\n if (config) {\r\n let defs = Array.from(svg.childNodes).find(v => (v as HTMLElement).tagName.toUpperCase() == 'DEFS')\r\n if (!defs) {\r\n defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')\r\n svg.appendChild(defs)\r\n }\r\n const element = document.createElementNS('http://www.w3.org/2000/svg', 'path')\r\n const size = (config.size || this.pluginOptions.text.size || 1)\r\n let pathR = this.pluginOptions.round ? textRadius - size / 3 : 0\r\n let pathL = this.pluginOptions.round ? lineSize : lineSize + (textRadius - size / 3)\r\n switch (postion) {\r\n case TextPosition.top:\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx} ${cy + pathR + pathL}\r\n h ${-pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${-pathR}\r\n v ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${-pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${pathR}\r\n v ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${pathR}\r\n h ${-pathL}`\r\n )\r\n break\r\n case TextPosition.bottom:\r\n if (this.pluginOptions.round)\r\n pathR += size * 2 / 3\r\n else\r\n pathL += size * 2 / 3\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx} ${cy - pathR - pathL}\r\n h ${-pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${-pathR} ${pathR}\r\n v ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${pathR} ${pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${pathR} ${-pathR}\r\n v ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${-pathR} ${-pathR}\r\n h ${-pathL}`\r\n )\r\n break\r\n case TextPosition.left:\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx + pathR + pathL} ${cy}\r\n v ${pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${pathR}\r\n h ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${-pathR}\r\n v ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${-pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${pathR}\r\n v ${pathL}`\r\n )\r\n break\r\n case TextPosition.right:\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx - pathR - pathL} ${cy}\r\n v ${-pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${-pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${pathR}\r\n v ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${pathR}\r\n h ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${-pathR}\r\n v ${-pathL}`\r\n )\r\n break\r\n }\r\n const id = `border-text-${postion}-${this.id}`\r\n element.setAttribute('id', id)\r\n element.setAttribute('fill', 'none')\r\n\r\n const span = document.createElementNS('http://www.w3.org/2000/svg', 'tspan')\r\n span.setAttribute('font-family', config.font || this.pluginOptions.text.font || 'sans-serif')\r\n span.setAttribute('fill', config.color || this.pluginOptions.text.color || '#000')\r\n span.setAttribute('font-weight', numToAttr(config.fontWeight || this.pluginOptions.text.fontWeight || 'normal'))\r\n span.setAttribute('font-style', config.fontStyle || this.pluginOptions.text.fontStyle || 'normal')\r\n span.setAttribute('font-size', numToAttr(size))\r\n span.textContent = config.content\r\n\r\n const textPath = document.createElementNS('http://www.w3.org/2000/svg', 'textPath')\r\n textPath.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#' + id)\r\n textPath.setAttribute('startOffset', '50%')\r\n textPath.setAttribute('text-anchor', 'middle')\r\n textPath.appendChild(span)\r\n\r\n const text = document.createElementNS('http://www.w3.org/2000/svg', 'text')\r\n text.appendChild(textPath)\r\n\r\n defs.appendChild(element)\r\n svg.appendChild(text)\r\n }\r\n })\r\n }\r\n}\r\n"],"names":["rx","numToAttr","value","toFixed","replace","svgPath","strings","values","reduce","t","v","i","p","trim","TextPosition","A","top","bottom","left","right","BorderPlugin","pluginOptions","id","constructor","Math","random","substring","this","postProcess","svg","options","document","thickness","size","margin","innerBorder","outerBorder","drawArea","extendSVG","padding","setAttribute","parseFloat","getAttribute","split","map","vb","join","length","cx","cy","lineSize","min","width","height","round","r","drawBorder","cfg","mid","pathR","pathL","element","createElementNS","color","dasharray","appendChild","textRadius","forEach","postion","config","defs","Array","from","childNodes","find","tagName","toUpperCase","text","span","font","fontWeight","fontStyle","textContent","content","textPath","setAttributeNS"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RecursivePartial } from '../types/helper.js';
|
|
2
2
|
import { Options } from '../utils/options.js';
|
|
3
|
-
export type ExtensionFunction = (svg:
|
|
3
|
+
export type ExtensionFunction = (svg: SVGSVGElement, options: Options) => void;
|
|
4
4
|
export declare class QRCodeStyling {
|
|
5
5
|
private options;
|
|
6
6
|
private container?;
|
|
@@ -20,7 +20,7 @@ export declare class QRCodeStyling {
|
|
|
20
20
|
/** This container will be used for appending of the QR code */
|
|
21
21
|
container?: HTMLElement): void;
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* @deprecated Use options.plugins
|
|
24
24
|
* @example
|
|
25
25
|
*
|
|
26
26
|
* ```js
|
|
@@ -48,6 +48,9 @@ export declare class QRCodeStyling {
|
|
|
48
48
|
applyExtension(
|
|
49
49
|
/** Extension is a function that takes svg and previously applied options and modifies an svg */
|
|
50
50
|
extension: ExtensionFunction): void;
|
|
51
|
+
/**
|
|
52
|
+
* @deprecated Use options.plugins
|
|
53
|
+
*/
|
|
51
54
|
deleteExtension(): void;
|
|
52
55
|
serialize(): Promise<string | undefined>;
|
|
53
56
|
private setupSvg;
|
package/lib/core/qr-svg.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Options } from '../utils/options.js';
|
|
|
3
3
|
export declare class QRSVG {
|
|
4
4
|
private options;
|
|
5
5
|
private _element;
|
|
6
|
-
get element():
|
|
6
|
+
get element(): SVGSVGElement;
|
|
7
7
|
private defs;
|
|
8
8
|
private backgroundMask?;
|
|
9
9
|
private backgroundMaskGroup?;
|
|
@@ -14,7 +14,7 @@ export declare class QRSVG {
|
|
|
14
14
|
private qr?;
|
|
15
15
|
private document;
|
|
16
16
|
private imageTools;
|
|
17
|
-
constructor(options: Pick<Options, 'width' | 'height' | 'document' | 'imageTools' | 'image' | 'imageOptions' | 'dotsOptions' | 'cornersDotOptions' | 'cornersSquareOptions' | 'backgroundOptions' | 'shape'> & {
|
|
17
|
+
constructor(options: Pick<Options, 'width' | 'height' | 'document' | 'imageTools' | 'image' | 'imageOptions' | 'dotsOptions' | 'cornersDotOptions' | 'cornersSquareOptions' | 'backgroundOptions' | 'shape' | 'plugins'> & {
|
|
18
18
|
errorCorrectionPercent: number;
|
|
19
19
|
});
|
|
20
20
|
get width(): number;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { DrawArgs } from '../types/helper.js';
|
|
2
|
-
import { CornerDotType } from '../utils/options.js';
|
|
2
|
+
import { CornerDotType, Plugin } from '../utils/options.js';
|
|
3
3
|
export declare function getQrCornerDotFigure(type: `${CornerDotType}`): (args: DrawArgs) => SVGElement;
|
|
4
|
+
export declare function drawPluginCornerDot(plugins: Plugin[]): (args: DrawArgs) => SVGElement | undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { DrawArgs } from '../types/helper.js';
|
|
2
|
-
import { CornerSquareType } from '../utils/options.js';
|
|
2
|
+
import { CornerSquareType, Plugin } from '../utils/options.js';
|
|
3
3
|
export declare function getQrCornerSquareFigure(type: `${CornerSquareType}`): (args: DrawArgs) => readonly [SVGPathElement, SVGPathElement];
|
|
4
|
+
export declare function drawPluginCornerSquare(plugins: Plugin[]): (args: DrawArgs) => readonly [SVGElement, SVGElement] | undefined;
|
package/lib/figures/dot.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { DrawArgs } from '../types/helper.js';
|
|
2
|
-
import { DotType } from '../utils/options.js';
|
|
3
|
-
export declare function getQrDotFigure(type: `${DotType}
|
|
2
|
+
import { DotType, Plugin } from '../utils/options.js';
|
|
3
|
+
export declare function getQrDotFigure(type: `${DotType}`, plugins?: Plugin[]): (args: DrawArgs) => SVGElement;
|
|
4
|
+
export declare function drawPluginDot(plugins: Plugin[]): (args: DrawArgs) => SVGElement | undefined;
|
|
@@ -6,5 +6,4 @@ export declare const SquareElements: {
|
|
|
6
6
|
classy: (args: BasicFigureDrawArgs) => readonly [SVGPathElement, SVGPathElement];
|
|
7
7
|
inpoint: (args: BasicFigureDrawArgs) => readonly [SVGPathElement, SVGPathElement];
|
|
8
8
|
centerCircle: (args: BasicFigureDrawArgs) => readonly [SVGPathElement, SVGPathElement];
|
|
9
|
-
cornerCut: (args: BasicFigureDrawArgs) => readonly [SVGPathElement, SVGPathElement];
|
|
10
9
|
};
|
package/lib/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { FileExtension } from './tools/browser-utils.js';
|
|
|
4
4
|
export { type RecursivePartial } from './types/helper.js';
|
|
5
5
|
export { type CanvasOptions } from './utils/canvas-options.js';
|
|
6
6
|
export { GradientType, type Gradient } from './utils/gradient.js';
|
|
7
|
-
export { CornerDotType, CornerSquareType, DotType, ImageMode, ShapeType, type Options } from './utils/options.js';
|
|
7
|
+
export { CornerDotType, CornerSquareType, DotType, ImageMode, ShapeType, type Options, type Plugin } from './utils/options.js';
|
|
8
8
|
export { ErrorCorrectionPercents } from './utils/qrcode.js';
|
|
9
9
|
import * as _browserUtils from './tools/browser-utils.js';
|
|
10
10
|
export declare const browserUtils: typeof _browserUtils | undefined;
|
package/lib/node.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { FileExtension } from './tools/browser-utils.js';
|
|
|
8
8
|
export { type RecursivePartial } from './types/helper.js';
|
|
9
9
|
export { type CanvasOptions } from './utils/canvas-options.js';
|
|
10
10
|
export { GradientType, type Gradient } from './utils/gradient.js';
|
|
11
|
-
export { CornerDotType, CornerSquareType, DotType, ImageMode, ShapeType, type Options } from './utils/options.js';
|
|
11
|
+
export { CornerDotType, CornerSquareType, DotType, ImageMode, ShapeType, type Options, type Plugin } from './utils/options.js';
|
|
12
12
|
export { ErrorCorrectionPercents } from './utils/qrcode.js';
|
|
13
13
|
export declare const browserUtils: typeof _browserUtils | undefined;
|
|
14
14
|
export declare class QRCodeStyling extends _QRCodeStyling {
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let t=/\.?0+$/;function e(e){return"string"==typeof e?e:e.toFixed(7).replace(t,"")}function r(t,r){t.setAttribute("width",e(parseFloat(t.getAttribute("width")||"0")+2*r)),t.setAttribute("height",e(parseFloat(t.getAttribute("height")||"0")+2*r));let i=(t.getAttribute("viewBox")||"").split(" ").map((t,e)=>parseFloat(t)+(e<2?-1:2)*r);if(t.setAttribute("viewBox",i.map(e).join(" ")),!(i.length<4))return{left:i[0],right:i[2]+i[0],top:i[1],bottom:i[3]+i[1]}}function i({draw:t,...r}){let{x:i,y:o,size:n,rotation:a=0}=r,u=i+n/2,s=o+n/2;return t=t(r),a&&(Array.isArray(t)?t:[t]).forEach(t=>t.setAttribute("transform",`rotate(${e(180*a/Math.PI)},${u},${s})`)),t}function o(t,{x:r,y:i,size:o}){let n=!1,a=0;return t.map(t=>"string"==typeof t?(a=0,n=t.toUpperCase()==t,t):(a++,t*=o,n&&(t+=a%2==1?r:i),e(t))).join(" ")}function n(t,...r){return t.reduce((t,i,o)=>{let n="";return o&&(n=r[o-1]),"number"==typeof n&&(n=e(n)),`${t}${n}${i}`},"").trim().replace(/[\s\n\r]+/gim," ")}export{r as extendSVG,e as numToAttr,i as rotateFigure,o as scalePath,n as svgPath};
|
|
2
|
+
//# sourceMappingURL=plugin-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-utils.js","sources":["../src/utils/svg.ts"],"sourcesContent":["import { RotateFigureArgs } from '../types/helper.js'\r\n\r\nconst rx = /\\.?0+$/\r\n\r\nexport function numToAttr(value: number | string) {\r\n if (typeof value == 'string') return value\r\n return value.toFixed(7).replace(rx, '')\r\n}\r\n\r\nexport function svgPath(strings: TemplateStringsArray, ...values: unknown[]) {\r\n return strings\r\n .reduce((t, v, i) => {\r\n let p: unknown = ''\r\n if (i) p = values[i - 1]\r\n if (typeof p == 'number') p = numToAttr(p)\r\n return `${t}${p}${v}`\r\n }, '')\r\n .trim()\r\n .replace(/[\\s\\n\\r]+/gim, ' ')\r\n}\r\n\r\nexport function rotateFigure<T extends SVGElement | ReadonlyArray<SVGElement>>({ draw, ...args }: RotateFigureArgs<T>) {\r\n const { x, y, size, rotation = 0 } = args\r\n const cx = x + size / 2\r\n const cy = y + size / 2\r\n\r\n const element = draw(args)\r\n if (rotation) (Array.isArray(element) ? element : [element])\r\n .forEach(el => el.setAttribute('transform', `rotate(${numToAttr((180 * rotation) / Math.PI)},${cx},${cy})`))\r\n return element\r\n}\r\n\r\nexport function scalePath(path: Array<string | number>, { x, y, size }: {\r\n x: number\r\n y: number\r\n size: number\r\n}) {\r\n let move = false\r\n let i = 0\r\n return path\r\n .map((v) => {\r\n if (typeof v == 'string') {\r\n i = 0\r\n move = v.toUpperCase() == v\r\n return v\r\n }\r\n i++\r\n v = v * size\r\n if (move) {\r\n v += i % 2 == 1 ? x : y\r\n }\r\n return numToAttr(v)\r\n })\r\n .join(' ')\r\n}\r\n\r\nexport function extendSVG(svg: SVGSVGElement, padding: number) {\r\n svg.setAttribute('width', numToAttr(parseFloat(svg.getAttribute('width') || '0') + 2 * padding))\r\n svg.setAttribute('height', numToAttr(parseFloat(svg.getAttribute('height') || '0') + 2 * padding))\r\n const vb = (svg.getAttribute('viewBox') || '').split(' ').map((v, i) => parseFloat(v) + (i < 2 ? -1 : 2) * padding)\r\n svg.setAttribute('viewBox', vb.map(numToAttr).join(' '))\r\n if (vb.length < 4)\r\n return undefined\r\n return {\r\n left: vb[0],\r\n right: vb[2] + vb[0],\r\n top: vb[1],\r\n bottom: vb[3] + vb[1]\r\n }\r\n}\r\n"],"names":["rx","numToAttr","value","toFixed","replace","extendSVG","svg","setAttribute","k","parseFloat","getAttribute","d","a","b","split","h","map","i","length","left","right","vb","top","bottom","rotateFigure","x","y","rotation","e","cy","args","forEach","element","Math","PI","l","scalePath","c","f","v","size","move","join","reduce","trim","svgPath"],"mappings":"AAEA,IAAAA,WAEMC,SAAUA,EAAUC,GACtB,MAAoB,mBAAiBA,EAC9BA,EAAMC,QAAQ,GAAGC,QAAQJ,EAAI,GAFQ,YAoD1CK,EAAAA,GAAAA,EAAoBC,aAClBC,QAAaC,EAAAC,0BAAkCC,eAAf,EAAwCC,IAAlDC,EAAAL,aACtBA,SAAaC,EAAAC,0BAAmCC,gBAAf,EAAyCC,IAAnD,IAAAE,GAC3BD,EAAAF,aAAYA,gBAAJI,MAAqCA,SAAE,CAAvCC,EAAgDC,IAAEP,WAASA,IAAAA,EAAA,GAAT,EAA2BQ,GAAAN,GACzD,GADyDC,EAA3BL,aACtDA,UAAaM,EAAAG,IAAjBR,GAA+BQ,KAAH,QAA5BH,EACAK,OAAOA,SAAP,CAEAC,KAAAN,EACIM,GAAAA,MADGN,EAEHO,GAAAA,EAAOC,GAAAC,IAAWT,EAFf,GAGHS,OACAC,EAAAA,GAAAA,EAAQF,GAAA,aA9CVG,KAAsBZ,KAAqDD,IAAM,IAA3Dc,EACxBZ,EAAAa,EAAAX,OAASW,EAAGC,gBAAMA,EAAUd,EAA5Be,EAAA,QAAA,EAMyGC,kBAFzFC,MAEXC,cADUnB,IAAyBoB,QACnCD,GAAAA,EAAAA,aAAiBxB,YAAa,kBAAuB0B,KAAiBN,OAAiBO,KAA5CC,OAChDvB,CAAA,CAAA,gBAGEwB,EAAAA,EAAAA,EAAAA,KAAkDrB,IAAA,IAAAa,GAAQ,EAAAS,EAAR,EAIvD,OACczB,EAAXI,IAEAsB,GACe,iBAALC,GACcF,EAAA,EAAAT,EAAhBU,8BAEWvB,EACAwB,IAEXtB,GAAAoB,EACIE,GAAIC,EACJC,KACcjC,EAAIiB,KAEtBiB,KAAA,IAAiBH,oBA1CN,OACnB3B,EAAA+B,OACKA,UAAWJ,IAAJF,EAAY,GAGhB,OAFAT,IAAiBS,EACbpB,EAAJW,EAAA,IACI,iBAAAS,QAAJA,IACA,GAAAxB,wBAEH+B,QACAxC,eAAQ,IAAA,QAT0DC,eAAAG,eAAAgB,kBAAAY,eAAAS"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Options, Plugin } from '../utils/options.js';
|
|
2
|
+
declare enum TextPosition {
|
|
3
|
+
top = "top",
|
|
4
|
+
bottom = "bottom",
|
|
5
|
+
left = "left",
|
|
6
|
+
right = "right"
|
|
7
|
+
}
|
|
8
|
+
export interface BorderConfig {
|
|
9
|
+
size: number;
|
|
10
|
+
color: string;
|
|
11
|
+
dasharray?: string;
|
|
12
|
+
margin?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface TextConfig {
|
|
15
|
+
font?: string;
|
|
16
|
+
color?: string;
|
|
17
|
+
size?: number;
|
|
18
|
+
fontWeight?: 'normal' | 'bold' | 'bolder' | 'lighter' | number;
|
|
19
|
+
fontStyle?: 'normal' | 'italic' | 'oblique';
|
|
20
|
+
}
|
|
21
|
+
export interface BorderPluginOptions extends BorderConfig {
|
|
22
|
+
/** Border roundnes, from 0 (square) to 1 (circle) */
|
|
23
|
+
round?: number;
|
|
24
|
+
text: TextConfig & {
|
|
25
|
+
[key in TextPosition]?: TextConfig & {
|
|
26
|
+
content: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
innerBorder?: BorderConfig;
|
|
30
|
+
outerBorder?: BorderConfig;
|
|
31
|
+
}
|
|
32
|
+
export declare class BorderPlugin implements Plugin {
|
|
33
|
+
private readonly pluginOptions;
|
|
34
|
+
private readonly id;
|
|
35
|
+
constructor(pluginOptions: BorderPluginOptions, id?: string);
|
|
36
|
+
postProcess(svg: SVGSVGElement, options: Options): void;
|
|
37
|
+
}
|
|
38
|
+
export {};
|