ReviewOS

also looking at this

stacks/ts-qr-codes

chore(deps): update dependency react to 19.2.7

#2137
Closed chris wants to merge buddy-bot/update-major-update-react into main
222 files +16350 -1825

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/react/package.jsonmodified+4-11
Changes to packages/react/package.json
@@ -2,7 +2,7 @@
22 "name": "react-qrx",
33 "type": "module",
44 "version": "0.1.0",
5 "description": "QR & Bar Code generating & reading. React components. Placeholder.",
5 "description": "QR & Bar Code generating & reading. React components.",
66 "author": "Chris Breuer <chris@stacksjs.org>",
77 "license": "MIT",
88 "homepage": "https://github.com/stacksjs/qrx/tree/main/packages/react#readme",
@@ -48,8 +48,6 @@
4848 ],
4949 "scripts": {
5050 "build": "echo 'coming soon'",
51 "lint": "bunx --bun eslint --flag unstable_ts_config .",
52 "lint:fix": "bunx --bun eslint --flag unstable_ts_config . --fix",
5351 "release": "bun publish --access public",
5452 "prepublishOnly": "bun --bun run build",
5553 "test": "bun test",
@@ -58,13 +56,8 @@
5856 "dependencies": {
5957 "@stacksjs/qrx": "workspace:*"
6058 },
61 "devDependencies": {
62 "@types/bun": "^1.1.14",
63 "lint-staged": "^16.2.3",
64 "simple-git-hooks": "^2.11.1",
65 "typescript": "^5.7.2"
66 },
67 "lint-staged": {
68 "*.{js,ts}": "bunx --bun eslint --flag unstable_ts_config . --fix"
59 "peerDependencies": {
60 "react": "^18.0.0 || ^19.0.0",
61 "react-dom": "^18.0.0 || ^19.0.0"
6962 }
7063}
packages/react/src/Barcode.tsxadded+132-0
Changes to packages/react/src/Barcode.tsx
@@ -0,0 +1,132 @@
1import type { BarcodeOptions } from '@stacksjs/qrx'
2import { barcode } from '@stacksjs/qrx'
3import { useCallback, useEffect, useRef, useState } from 'react'
4
5export interface BarcodeProps {
6 value: string | number
7 format?: string
8 width?: string | number
9 height?: string | number
10 displayValue?: string | boolean
11 text?: string | number
12 fontOptions?: string
13 font?: string
14 textAlign?: string
15 textPosition?: string
16 textMargin?: string | number
17 fontSize?: string | number
18 background?: string
19 lineColor?: string
20 margin?: string | number
21 marginTop?: string | number
22 marginBottom?: string | number
23 marginLeft?: string | number
24 marginRight?: string | number
25 flat?: boolean
26 ean128?: string | boolean
27 elementTag?: 'svg' | 'canvas' | 'img'
28 onValid?: (valid: boolean) => void
29 children?: React.ReactNode
30}
31
32export function Barcode({
33 value,
34 format,
35 width,
36 height,
37 displayValue = true,
38 text,
39 fontOptions,
40 font,
41 textAlign,
42 textPosition,
43 textMargin,
44 fontSize,
45 background,
46 lineColor,
47 margin,
48 marginTop,
49 marginBottom,
50 marginLeft,
51 marginRight,
52 flat,
53 ean128,
54 elementTag = 'svg',
55 onValid,
56 children,
57}: BarcodeProps): React.JSX.Element {
58 const elementRef = useRef<HTMLElement>(null)
59 const [valid, setValid] = useState(true)
60
61 const renderBarcode = useCallback(() => {
62 const el = elementRef.current
63 if (!el)
64 return
65
66 const settings: BarcodeOptions = {
67 format,
68 width,
69 height,
70 displayValue,
71 text,
72 fontOptions,
73 font,
74 textAlign,
75 textPosition,
76 textMargin,
77 fontSize,
78 background,
79 lineColor,
80 margin,
81 marginTop,
82 marginBottom,
83 marginLeft,
84 marginRight,
85 flat,
86 ean128,
87 elementTag,
88 valid: (v: boolean) => {
89 setValid(v)
90 onValid?.(v)
91 },
92 }
93
94 // Remove undefined props so the barcode lib uses its defaults
95 for (const key of Object.keys(settings) as Array<keyof BarcodeOptions>) {
96 if (settings[key] === undefined)
97 delete settings[key]
98 }
99
100 try {
101 barcode(el, String(value), settings)
102 }
103 catch {
104 setValid(false)
105 onValid?.(false)
106 }
107 }, [
108 value, format, width, height, displayValue, text, fontOptions, font,
109 textAlign, textPosition, textMargin, fontSize, background, lineColor,
110 margin, marginTop, marginBottom, marginLeft, marginRight, flat, ean128,
111 elementTag, onValid,
112 ])
113
114 useEffect(() => {
115 renderBarcode()
116 }, [renderBarcode])
117
118 const Element = elementTag
119
120 return (
121 <div>
122 <Element
123 ref={elementRef as any}
124 className="react-barcode-element"
125 style={{ display: valid ? undefined : 'none' }}
126 />
127 {!valid && children && (
128 <div>{children}</div>
129 )}
130 </div>
131 )
132}
packages/react/src/QRCode.tsxadded+72-0
Changes to packages/react/src/QRCode.tsx
@@ -0,0 +1,72 @@
1import type { QRCodeOptions } from '@stacksjs/qrx'
2import { QRCode as QRCodeGenerator, QRErrorCorrectLevel } from '@stacksjs/qrx'
3import { useCallback, useEffect, useRef, useState } from 'react'
4
5export interface QRCodeProps {
6 value: string
7 width?: number
8 height?: number
9 colorDark?: string
10 colorLight?: string
11 correctLevel?: QRErrorCorrectLevel
12 useSVG?: boolean
13 children?: React.ReactNode
14}
15
16export function QRCode({
17 value,
18 width = 256,
19 height = 256,
20 colorDark = '#000000',
21 colorLight = '#ffffff',
22 correctLevel = QRErrorCorrectLevel.M,
23 useSVG = false,
24 children,
25}: QRCodeProps): React.JSX.Element {
26 const containerRef = useRef<HTMLDivElement>(null)
27 const [valid, setValid] = useState(true)
28
29 const renderQRCode = useCallback(() => {
30 const el = containerRef.current
31 if (!el)
32 return
33
34 // Clear previous render
35 el.innerHTML = ''
36
37 const options: QRCodeOptions = {
38 text: value,
39 width,
40 height,
41 colorDark,
42 colorLight,
43 correctLevel,
44 useSVG,
45 }
46
47 try {
48 new QRCodeGenerator(el, options)
49 setValid(true)
50 }
51 catch {
52 setValid(false)
53 }
54 }, [value, width, height, colorDark, colorLight, correctLevel, useSVG])
55
56 useEffect(() => {
57 renderQRCode()
58 }, [renderQRCode])
59
60 return (
61 <div>
62 <div
63 ref={containerRef}
64 className="react-qrcode-element"
65 style={{ display: valid ? undefined : 'none' }}
66 />
67 {!valid && children && (
68 <div>{children}</div>
69 )}
70 </div>
71 )
72}
packages/react/src/index.tsadded+5-0
Changes to packages/react/src/index.ts
@@ -0,0 +1,5 @@
1export { Barcode } from './Barcode'
2export type { BarcodeProps } from './Barcode'
3export { QRCode } from './QRCode'
4export type { QRCodeProps } from './QRCode'
5export { QRErrorCorrectLevel } from '@stacksjs/qrx'
packages/react/tsconfig.jsonadded+8-0
Changes to packages/react/tsconfig.json
@@ -0,0 +1,8 @@
1{
2 "extends": "../../tsconfig.json",
3 "compilerOptions": {
4 "jsx": "react-jsx",
5 "types": ["react", "react-dom"]
6 },
7 "include": ["src"]
8}
packages/vue/index.tsmodified+167-155
Changes to packages/vue/index.ts
@@ -1,188 +1,200 @@
1import type { BarcodeOptions } from '@stacksjs/qrx'
2import type { Component, PropType } from 'vue'
3import { barcode } from '@stacksjs/qrx'
4import { defineComponent, h } from 'vue'
1import type { BarcodeOptions, QRCodeOptions } from '@stacksjs/qrx'
2import { barcode, QRCode, QRErrorCorrectLevel } from '@stacksjs/qrx'
3import { defineComponent, h, onMounted, ref, watch } from 'vue'
54
6interface BarcodeData {
7 valid: boolean
8}
9
10export const VueBarcode: Component = defineComponent({
5export const VueBarcode = defineComponent({
116 name: 'VueBarcode',
127
13 render() {
14 return h('div', [
15 h(this.elementTag, {
16 style: { display: this.valid ? undefined : 'none' },
17 class: ['vue-barcode-element'],
18 }),
19
20 h('div', {
21 style: { display: this.valid ? 'none' : undefined },
22 }, this.$slots.default?.()),
23 ])
24 },
25
268 props: {
279 value: {
28 type: [String, Number] as PropType<string | number>,
10 type: [String, Number],
2911 required: true,
3012 },
31
32 format: {
33 type: String as PropType<string>,
34 },
35
36 width: {
37 type: [String, Number] as PropType<string | number>,
38 },
39
40 height: {
41 type: [String, Number] as PropType<string | number>,
42 },
43
13 format: String,
14 width: [String, Number],
15 height: [String, Number],
4416 displayValue: {
45 type: [String, Boolean] as PropType<string | boolean>,
17 type: [String, Boolean],
4618 default: true,
4719 },
48
49 text: {
50 type: [String, Number] as PropType<string | number>,
51 },
52
53 fontOptions: {
54 type: String as PropType<string>,
55 },
56
57 font: {
58 type: String as PropType<string>,
59 },
60
61 textAlign: {
62 type: String as PropType<string>,
63 },
64
65 textPosition: {
66 type: String as PropType<string>,
67 },
68
69 textMargin: {
70 type: [String, Number] as PropType<string | number>,
20 text: [String, Number],
21 fontOptions: String,
22 font: String,
23 textAlign: String,
24 textPosition: String,
25 textMargin: [String, Number],
26 fontSize: [String, Number],
27 background: String,
28 lineColor: String,
29 margin: [String, Number],
30 marginTop: [String, Number],
31 marginBottom: [String, Number],
32 marginLeft: [String, Number],
33 marginRight: [String, Number],
34 flat: Boolean,
35 ean128: [String, Boolean],
36 elementTag: {
37 type: String,
38 default: 'svg',
39 validator: (value: string) => ['canvas', 'svg', 'img'].includes(value),
7140 },
41 },
7242
73 fontSize: {
74 type: [String, Number] as PropType<string | number>,
75 },
43 setup(props, { slots }) {
44 const valid = ref(true)
45 const elementRef = ref<HTMLElement | null>(null)
7646
77 background: {
78 type: String as PropType<string>,
79 },
47 function renderBarcode() {
48 const el = elementRef.value
49 if (!el)
50 return
8051
81 lineColor: {
82 type: String as PropType<string>,
83 },
52 const settings: BarcodeOptions = {
53 format: props.format,
54 width: props.width,
55 height: props.height,
56 displayValue: props.displayValue,
57 text: props.text,
58 fontOptions: props.fontOptions,
59 font: props.font,
60 textAlign: props.textAlign,
61 textPosition: props.textPosition,
62 textMargin: props.textMargin,
63 fontSize: props.fontSize,
64 background: props.background,
65 lineColor: props.lineColor,
66 margin: props.margin,
67 marginTop: props.marginTop,
68 marginBottom: props.marginBottom,
69 marginLeft: props.marginLeft,
70 marginRight: props.marginRight,
71 flat: props.flat,
72 ean128: props.ean128,
73 elementTag: props.elementTag,
74 valid: (v: boolean) => {
75 valid.value = v
76 },
77 }
8478
85 margin: {
86 type: [String, Number] as PropType<string | number>,
87 },
79 // Remove undefined props so the barcode lib uses its defaults
80 for (const key of Object.keys(settings) as Array<keyof BarcodeOptions>) {
81 if (settings[key] === undefined)
82 delete settings[key]
83 }
8884
89 marginTop: {
90 type: [String, Number] as PropType<string | number>,
91 },
85 try {
86 barcode(el, String(props.value), settings)
87 }
88 catch {
89 valid.value = false
90 }
91 }
9292
93 marginBottom: {
94 type: [String, Number] as PropType<string | number>,
95 },
93 onMounted(renderBarcode)
9694
97 marginLeft: {
98 type: [String, Number] as PropType<string | number>,
99 },
95 watch(() => ({ ...props }), renderBarcode, { deep: true })
10096
101 marginRight: {
102 type: [String, Number] as PropType<string | number>,
103 },
97 return () => h('div', [
98 h(props.elementTag, {
99 ref: (el: any) => { elementRef.value = el },
100 style: { display: valid.value ? undefined : 'none' },
101 class: 'vue-barcode-element',
102 }),
103 h('div', {
104 style: { display: valid.value ? 'none' : undefined },
105 }, slots.default?.()),
106 ])
107 },
108})
104109
105 flat: {
106 type: Boolean as PropType<boolean>,
107 },
110export const VueQRCode = defineComponent({
111 name: 'VueQRCode',
108112
109 ean128: {
110 type: [String, Boolean] as PropType<string | boolean>,
113 props: {
114 value: {
115 type: String,
116 required: true,
111117 },
112
113 elementTag: {
114 type: String as PropType<string>,
115 default: 'svg',
116 validator(value: string): boolean {
117 return ['canvas', 'svg', 'img'].includes(value)
118 },
118 width: {
119 type: Number,
120 default: 256,
119121 },
120 },
121
122 data(): BarcodeData {
123 return { valid: true }
124 },
125
126 watch: {
127 $props: {
128 handler() {
129 this.renderBarcode()
130 },
131 deep: true,
132 immediate: true,
122 height: {
123 type: Number,
124 default: 256,
125 },
126 colorDark: {
127 type: String,
128 default: '#000000',
129 },
130 colorLight: {
131 type: String,
132 default: '#ffffff',
133 },
134 correctLevel: {
135 type: Number,
136 default: QRErrorCorrectLevel.M,
137 validator: (value: number) => [
138 QRErrorCorrectLevel.L,
139 QRErrorCorrectLevel.M,
140 QRErrorCorrectLevel.Q,
141 QRErrorCorrectLevel.H,
142 ].includes(value),
143 },
144 useSVG: {
145 type: Boolean,
146 default: false,
133147 },
134148 },
135149
136 mounted() {
137 this.renderBarcode()
138 },
150 setup(props, { slots }) {
151 const containerRef = ref<HTMLElement | null>(null)
152 const valid = ref(true)
153 let qrInstance: QRCode | null = null
154
155 function renderQRCode() {
156 const el = containerRef.value
157 if (!el)
158 return
159
160 // Clear previous render
161 el.innerHTML = ''
162
163 const options: QRCodeOptions = {
164 text: props.value,
165 width: props.width,
166 height: props.height,
167 colorDark: props.colorDark,
168 colorLight: props.colorLight,
169 correctLevel: props.correctLevel,
170 useSVG: props.useSVG,
171 }
139172
140 methods: {
141 renderBarcode() {
142 const settings: BarcodeOptions = {
143 format: this.format,
144 width: this.width,
145 height: this.height,
146 displayValue: this.displayValue,
147 text: this.text,
148 fontOptions: this.fontOptions,
149 font: this.font,
150 textAlign: this.textAlign,
151 textPosition: this.textPosition,
152 textMargin: this.textMargin,
153 fontSize: this.fontSize,
154 background: this.background,
155 lineColor: this.lineColor,
156 margin: this.margin,
157 marginTop: this.marginTop,
158 marginBottom: this.marginBottom,
159 marginLeft: this.marginLeft,
160 marginRight: this.marginRight,
161 flat: this.flat,
162 ean128: this.ean128,
163 valid: (valid: boolean) => {
164 this.valid = valid
165 },
166 elementTag: this.elementTag,
173 try {
174 qrInstance = new QRCode(el, options)
175 valid.value = true
176 }
177 catch {
178 valid.value = false
179 qrInstance = null
167180 }
181 }
168182
169 this.removeUndefinedProps(settings)
183 onMounted(renderQRCode)
170184
171 const element = this.$el.querySelector('.vue-barcode-element')
172 if (element) {
173 barcode(element, String(this.value), settings)
174 }
175 },
185 watch(() => ({ ...props }), renderQRCode, { deep: true })
176186
177 removeUndefinedProps(obj: BarcodeOptions): void {
178 for (const prop in obj) {
179 if (Object.prototype.hasOwnProperty.call(obj, prop)) {
180 const value = obj[prop as keyof BarcodeOptions]
181 if (value === undefined) {
182 delete obj[prop as keyof BarcodeOptions]
183 }
184 }
185 }
186 },
187 return () => h('div', [
188 h('div', {
189 ref: (el: any) => { containerRef.value = el },
190 class: 'vue-qrcode-element',
191 style: { display: valid.value ? undefined : 'none' },
192 }),
193 h('div', {
194 style: { display: valid.value ? 'none' : undefined },
195 }, slots.default?.()),
196 ])
187197 },
188198})
199
200export { QRErrorCorrectLevel } from '@stacksjs/qrx'
packages/vue/package.jsonmodified+2-10
Changes to packages/vue/package.json
@@ -48,8 +48,6 @@
4848 ],
4949 "scripts": {
5050 "build": "echo 'coming soon'",
51 "lint": "bunx --bun eslint --flag unstable_ts_config .",
52 "lint:fix": "bunx --bun eslint --flag unstable_ts_config . --fix",
5351 "release": "bun publish --access public",
5452 "prepublishOnly": "bun --bun run build",
5553 "test": "bun test",
@@ -58,13 +56,7 @@
5856 "dependencies": {
5957 "@stacksjs/qrx": "workspace:*"
6058 },
61 "devDependencies": {
62 "@types/bun": "^1.1.14",
63 "lint-staged": "^16.2.3",
64 "simple-git-hooks": "^2.11.1",
65 "typescript": "^5.7.2"
66 },
67 "lint-staged": {
68 "*.{js,ts}": "bunx --bun eslint --flag unstable_ts_config . --fix"
59 "peerDependencies": {
60 "vue": "^3.5.0"
6961 }
7062}
tsconfig.jsonmodified+3-1
Changes to tsconfig.json
@@ -28,6 +28,8 @@
2828 "node_modules",
2929 "**/dist",
3030 "**/quagga/**",
31 "test/**"
31 "test/**",
32 "packages/react/**",
33 "packages/vue/**"
3234 ]
3335}