@liquid-js/qr-code-styling 5.0.0-2 → 5.0.0-4
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 +71 -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 +34 -0
- package/lib/plugins/utils.d.ts +2 -0
- package/lib/qr-code-styling-node.js +475 -417
- 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
|
@@ -74,6 +74,77 @@ Try it here <https://styled-qr.liquidjs.io/>
|
|
|
74
74
|
</html>
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
### Plugins <img align="right" src="https://raw.githubusercontent.com/Liquid-JS/qr-code-styling/master/src/assets/border.png" width="240" />
|
|
78
|
+
|
|
79
|
+
Version `5.0.0` of the library introduces plugin support to replace the now-deprecated `QRCodeStyling.extension`, with the ability to customize the shape of dots and corners. Existing extensions can still be applied as `plugins: [{ postProcess: extensionFn }]`.
|
|
80
|
+
|
|
81
|
+
While the old API only supports a single extension, it is now possible to apply multiple plugins or even multiple instances of a single plugin. For example, to create a QR code with a complex border:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { BorderPlugin } from '@liquid-js/qr-code-styling/border-plugin'
|
|
85
|
+
|
|
86
|
+
const qrCode = new QRCodeStyling({
|
|
87
|
+
plugins: [
|
|
88
|
+
new BorderPlugin({
|
|
89
|
+
round: 1,
|
|
90
|
+
size: 2,
|
|
91
|
+
color: '#20c9dc'
|
|
92
|
+
}),
|
|
93
|
+
new BorderPlugin({
|
|
94
|
+
round: 1,
|
|
95
|
+
size: 60,
|
|
96
|
+
color: '#4267b2',
|
|
97
|
+
text: {
|
|
98
|
+
font: 'sans-serif',
|
|
99
|
+
color: '#e9ebee',
|
|
100
|
+
size: 30,
|
|
101
|
+
top: {
|
|
102
|
+
content: 'Scan the'.toUpperCase()
|
|
103
|
+
},
|
|
104
|
+
bottom: {
|
|
105
|
+
content: 'QR code'.toUpperCase()
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
]
|
|
110
|
+
// ...other options
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### Plugin development
|
|
115
|
+
|
|
116
|
+
A simple plugin example to customize QR code dots:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { svgPath, DrawArgs } from '@liquid-js/qr-code-styling/plugin-utils'
|
|
120
|
+
|
|
121
|
+
const qrCode = new QRCodeStyling({
|
|
122
|
+
plugins: [
|
|
123
|
+
{
|
|
124
|
+
drawDot: (args: DrawArgs): SVGElement | undefined => {
|
|
125
|
+
const { size, x, y, document } = args
|
|
126
|
+
|
|
127
|
+
const element = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
|
128
|
+
// Insert your own SVG path definition, or implement neighbour-aware logic through args.getNeighbor()
|
|
129
|
+
element.setAttribute(
|
|
130
|
+
'd',
|
|
131
|
+
svgPath`M ${x} ${y + (size - size) / 2}
|
|
132
|
+
v ${size}
|
|
133
|
+
h ${size / 2}
|
|
134
|
+
a ${size / 2} ${size / 2} 0 0 0 0 ${-size}
|
|
135
|
+
z`
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
return element
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
]
|
|
142
|
+
// ...other options
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
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.
|
|
147
|
+
|
|
77
148
|
### Node
|
|
78
149
|
|
|
79
150
|
> ⚠️ **Note**: make sure to install peer dependencies when running on Node (not needed for browser environments)
|
|
@@ -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,s)=>{let o="";return s&&(o=i[s-1]),"number"==typeof o&&(o=e(o)),`${t}${o}${r}`},"").trim().replace(/[\s\n\r]+/gim," ")}var r,s=r||={};s.top="top",s.bottom="bottom",s.left="left",s.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,s){let{document:o}=s,$=this.pluginOptions.size,n=function(t,i){i=Math.max(i,0),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,$+(this.pluginOptions.margin||0));if(n){$=Math.abs($);var a=(n.left+n.right)/2,h=(n.top+n.bottom)/2,p=Math.min(s.width,s.height)/2*(1-(this.pluginOptions.round||0)),l=Math.min(n.right-n.left-2*$,n.bottom-n.top-2*$)/2-p+$/2,u=this.pluginOptions.round?l:0,g=this.pluginOptions.round?p:p+l;(s=o.createElementNS("http://www.w3.org/2000/svg","rect")).setAttribute("width",e(2*(g+u))),s.setAttribute("height",e(2*(g+u))),s.setAttribute("x",e(a-g-u)),s.setAttribute("y",e(h-g-u)),s.setAttribute("rx",e(u)),s.setAttribute("fill","none"),s.setAttribute("stroke",this.pluginOptions.color),s.setAttribute("stroke-width",e($)),this.pluginOptions.dasharray&&s.setAttribute("stroke-dasharray",this.pluginOptions.dasharray),t.appendChild(s),[r.left,r.top,r.right,r.bottom].forEach(s=>{var $=this.pluginOptions.text,n=$?.[s];if(n){let d=Array.from(t.childNodes).find(t=>"DEFS"==t.tagName.toUpperCase());d||(d=o.createElementNS("http://www.w3.org/2000/svg","defs"),t.appendChild(d));let b=o.createElementNS("http://www.w3.org/2000/svg","path"),f=n.size||$.size||1;switch(u=this.pluginOptions.round?l-f/3:0,g=this.pluginOptions.round?p:p+(l-f/3),s){case r.top:b.setAttribute("d",i`M ${a} ${h+u+g} h ${-g} a ${u} ${u} 0 0 1 ${-u} ${-u} v ${-2*g} a ${u} ${u} 0 0 1 ${u} ${-u} h ${2*g} a ${u} ${u} 0 0 1 ${u} ${u} v ${2*g} a ${u} ${u} 0 0 1 ${-u} ${u} h ${-g}`);break;case r.bottom:this.pluginOptions.round?u+=2*f/3:g+=2*f/3,b.setAttribute("d",i`M ${a} ${h-u-g} h ${-g} a ${u} ${u} 0 0 0 ${-u} ${u} v ${2*g} a ${u} ${u} 0 0 0 ${u} ${u} h ${2*g} a ${u} ${u} 0 0 0 ${u} ${-u} v ${-2*g} a ${u} ${u} 0 0 0 ${-u} ${-u} h ${-g}`);break;case r.left:b.setAttribute("d",i`M ${a+u+g} ${h} v ${g} a ${u} ${u} 0 0 1 ${-u} ${u} h ${-2*g} a ${u} ${u} 0 0 1 ${-u} ${-u} v ${-2*g} a ${u} ${u} 0 0 1 ${u} ${-u} h ${2*g} a ${u} ${u} 0 0 1 ${u} ${u} v ${g}`);break;case r.right:b.setAttribute("d",i`M ${a-u-g} ${h} v ${-g} a ${u} ${u} 0 0 1 ${u} ${-u} h ${2*g} a ${u} ${u} 0 0 1 ${u} ${u} v ${2*g} a ${u} ${u} 0 0 1 ${-u} ${u} h ${-2*g} a ${u} ${u} 0 0 1 ${-u} ${-u} v ${-g}`)}s=`border-text-${s}-${this.id}`,b.setAttribute("id",s),b.setAttribute("fill","none");let w=o.createElementNS("http://www.w3.org/2000/svg","tspan");w.setAttribute("font-family",n.font||$.font||"sans-serif"),w.setAttribute("fill",n.color||$.color||"#000"),w.setAttribute("font-weight",e(n.fontWeight||$.fontWeight||"normal")),w.setAttribute("font-style",n.fontStyle||$.fontStyle||"normal"),w.setAttribute("font-size",e(f)),w.textContent=n.content,($=o.createElementNS("http://www.w3.org/2000/svg","textPath")).setAttributeNS("http://www.w3.org/1999/xlink","xlink:href","#"+s),$.setAttribute("startOffset","50%"),$.setAttribute("text-anchor","middle"),$.appendChild(w),(n=o.createElementNS("http://www.w3.org/2000/svg","text")).appendChild($),d.appendChild(b),t.appendChild(n)}})}}};
|
|
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 padding = Math.max(padding, 0)\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 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 {\r\n /** Border roundnes, from 0 (square) to 1 (circle) */\r\n round?: number\r\n size: number\r\n color: string\r\n dasharray?: string\r\n margin?: number\r\n text?: TextConfig & {\r\n [key in TextPosition]?: TextConfig & {\r\n content: string\r\n }\r\n }\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 margin = this.pluginOptions.margin || 0\r\n let thickness = this.pluginOptions.size\r\n const drawArea = extendSVG(svg, thickness + margin)\r\n if (!drawArea)\r\n return\r\n\r\n thickness = Math.abs(thickness)\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 const r = (Math.min(drawArea.right - drawArea.left - 2 * thickness, drawArea.bottom - drawArea.top - 2 * thickness) / 2) - lineSize + thickness / 2\r\n\r\n let pathR = this.pluginOptions.round ? r : 0\r\n let pathL = this.pluginOptions.round ? lineSize : lineSize + r\r\n\r\n const borderEl = document.createElementNS('http://www.w3.org/2000/svg', 'rect')\r\n borderEl.setAttribute('width', numToAttr((pathL + pathR) * 2))\r\n borderEl.setAttribute('height', numToAttr((pathL + pathR) * 2))\r\n borderEl.setAttribute('x', numToAttr(cx - pathL - pathR))\r\n borderEl.setAttribute('y', numToAttr(cy - pathL - pathR))\r\n borderEl.setAttribute('rx', numToAttr(pathR))\r\n borderEl.setAttribute('fill', 'none')\r\n borderEl.setAttribute('stroke', this.pluginOptions.color)\r\n borderEl.setAttribute('stroke-width', numToAttr(thickness))\r\n if (this.pluginOptions.dasharray) {\r\n borderEl.setAttribute('stroke-dasharray', this.pluginOptions.dasharray)\r\n }\r\n\r\n svg.appendChild(borderEl);\r\n\r\n [TextPosition.left, TextPosition.top, TextPosition.right, TextPosition.bottom].forEach(postion => {\r\n const textCfg = this.pluginOptions.text\r\n const config = textCfg?.[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 || textCfg.size || 1)\r\n pathR = this.pluginOptions.round ? r - size / 3 : 0\r\n pathL = this.pluginOptions.round ? lineSize : lineSize + (r - 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 || textCfg.font || 'sans-serif')\r\n span.setAttribute('fill', config.color || textCfg.color || '#000')\r\n span.setAttribute('font-weight', numToAttr(config.fontWeight || textCfg.fontWeight || 'normal'))\r\n span.setAttribute('font-style', config.fontStyle || textCfg.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","B","top","bottom","left","right","pluginOptions","id","constructor","Math","random","substring","this","postProcess","svg","options","document","thickness","size","drawArea","extendSVG","padding","max","setAttribute","parseFloat","getAttribute","split","map","vb","join","length","margin","abs","cx","cy","lineSize","min","width","height","round","pathR","r","pathL","borderEl","createElementNS","color","dasharray","appendChild","forEach","postion","text","textCfg","config","defs","Array","from","childNodes","find","tagName","toUpperCase","element","span","font","fontWeight","fontStyle","textContent","content","setAttributeNS","textPath"],"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 with a postProcess hook
|
|
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 with a postProcess hook
|
|
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){r=Math.max(r,0),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 padding = Math.max(padding, 0)\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","padding","max","k","parseFloat","c","a","setAttribute","getAttribute","b","split","h","map","i","length","left","right","vb","top","bottom","e","d","f","size","rotation","isArray","draw","args","forEach","Math","PI","cy","element","scalePath","path","y","v","toUpperCase","reduce","trim","rotateFigure","svgPath"],"mappings":"AAEA,IAAAA,WAEMC,SAAUA,EAAUC,GACtB,MAAoB,iBAATA,EAA0BA,EAC9BA,EAAMC,QAAQ,GAAGC,QAAQJ,EAAI,GAFQ,YAoD1CK,EAAAA,GAAAA,EAAoBC,KACtBC,MAAeC,GAAAA,EAAID,qBACFE,EAAAC,WAAmBA,EAAAA,uBAA4B,KAA5B,EAAwCC,IAAlDC,EAAAC,aACtBA,SAAaJ,EAAAC,WAAoBA,EAAAA,aAAeI,WAAa,KAA5B,EAAyCH,IAAnD,IAAAI,GAC3BH,EAAAE,aAAYA,gBAAJE,MAAqCA,KAAAA,KAArCC,EAAgDC,IAAER,WAASA,IAAAA,EAAA,GAAT,EAA2BS,GAAAR,GACzD,GADyDC,EAA3BC,uBACzCE,EAAAG,IAAjBT,GAA+BS,KAAH,QAA5BH,SACOK,GAAAA,MAAP,CAEAC,KAAAN,EACIM,GAAAA,MADGN,EAEHO,GAAAA,EAAOC,GAAAC,IAAWT,EAFf,GAGHS,OACAC,EAAAA,GAAAA,EAAQF,GAAA,qCA/C+DN,OAAAS,WAC3EC,EAAM,GAANhB,EAASiB,EAATb,EAAYW,EAAA,EAAAG,EAAMZ,EAAAS,EAAA,EAMyDI,OANzDlB,EAAAA,EAAAD,GAAlBgB,UAAAI,WAIaC,EAAGC,CAAHrB,IACbsB,QAAqBH,kBAChBG,YAAiBrB,UAAAA,EAAAA,IAAac,EAAAQ,KAAAC,mBAAyDA,CAAAA,CAA5C,SAAyDC,EACzGzB,GAAO0B,EAR0G3B,mBAW/G4B,SAAoBC,OAAmC5B,EAAA6B,IAAGb,oBAKjDA,GAGDc,EAAD,EACDhB,EAAAE,EAAIe,eAAYf,EAAhBA,IAGID,IAAAC,GAAOc,EAAAA,IADEC,GAAAA,EAAAA,GAAAA,EAAAA,EAAF5B,GAGXN,YAEA,IACa,oBAxCF,OACnBG,EAAAgC,OACKA,UAAWF,IAAJf,EAAY,GAGhB,OAFAD,IAAiBC,EACbR,EAAJO,EAAA,IACI,iBAAAC,QAAJA,IACA,GAAAZ,wBAEH8B,QACAzC,eAAQ,IAAA,QAT0DC,eAAAI,eAAAqC,kBAAAP,eAAAQ"}
|
|
@@ -0,0 +1,34 @@
|
|
|
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 TextConfig {
|
|
9
|
+
font?: string;
|
|
10
|
+
color?: string;
|
|
11
|
+
size?: number;
|
|
12
|
+
fontWeight?: 'normal' | 'bold' | 'bolder' | 'lighter' | number;
|
|
13
|
+
fontStyle?: 'normal' | 'italic' | 'oblique';
|
|
14
|
+
}
|
|
15
|
+
export interface BorderPluginOptions {
|
|
16
|
+
/** Border roundnes, from 0 (square) to 1 (circle) */
|
|
17
|
+
round?: number;
|
|
18
|
+
size: number;
|
|
19
|
+
color: string;
|
|
20
|
+
dasharray?: string;
|
|
21
|
+
margin?: number;
|
|
22
|
+
text?: TextConfig & {
|
|
23
|
+
[key in TextPosition]?: TextConfig & {
|
|
24
|
+
content: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export declare class BorderPlugin implements Plugin {
|
|
29
|
+
private readonly pluginOptions;
|
|
30
|
+
private readonly id;
|
|
31
|
+
constructor(pluginOptions: BorderPluginOptions, id?: string);
|
|
32
|
+
postProcess(svg: SVGSVGElement, options: Options): void;
|
|
33
|
+
}
|
|
34
|
+
export {};
|