@particle-academy/react-fancy 5.35.1 → 5.36.1

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
@@ -11,6 +11,87 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [5.36.1] - 2026-10-11
15
+
16
+ ### Security
17
+
18
+ - **`encodeQr` spent linear time on a value it was always going to refuse.**
19
+ `<QrCode>` renders a `value` the component did not author, and version
20
+ selection walked versions 1–40 re-encoding the payload at each one — so a
21
+ value too long to fit was encoded **forty times** before being rejected.
22
+ Measured on the built bundle: **342 ms for 100 kB, 2.0 s for 500 kB**,
23
+ linear, which is tens of seconds of blocked main thread for a few megabytes
24
+ through `<QrCode value={userInput} />`.
25
+
26
+ The refusal was always correct; the *cost* of the refusal was the defect. An
27
+ impossible value is now rejected from `value.length` alone — a character
28
+ count can never exceed a byte count, so a string longer than the largest
29
+ capacity any mode offers cannot fit in any of them. **500 kB now refuses in
30
+ 0.0 ms**, and the legitimate path got faster too (the payload's bit length
31
+ depends on the version only through the character-count indicator, which has
32
+ three tiers, so it is computed at most three times rather than forty).
33
+
34
+ **Nothing to do** — the API, the thrown `RangeError` and every value that
35
+ previously encoded are unchanged, boundary cases included (2,953 bytes still
36
+ encodes; 2,954 still throws).
37
+
38
+ Worth stating why this was treated as a security fix rather than a
39
+ performance note: this encoder reaches consumers **as vendored source** via
40
+ `npx fancy-cli add qr-code`, not only as a package. Vendored source carries
41
+ no manifest, so no advisory, Dependabot alert or audit row would ever have
42
+ named it — the only time to fix it is before anyone copies it in.
43
+
44
+ ## [5.36.0] - 2026-10-11
45
+
46
+ ### Added
47
+
48
+ - **`<QrCode>` — a QR code as an SVG, with no dependencies.** ISO/IEC 18004,
49
+ versions 1–40, error correction L/M/Q/H, and numeric / alphanumeric / byte
50
+ modes selected automatically. **Nothing to do** — it is a new component and
51
+ nothing else changed.
52
+
53
+ ```tsx
54
+ <QrCode value="https://host/pair#482913" size={192} label="Pair this device" />
55
+ ```
56
+
57
+ `label` is required. A QR code is unusable to anyone who cannot point a second
58
+ device at the screen, so it needs an accessible name describing the
59
+ *destination* — and the value should also appear as text or a link nearby,
60
+ which an `aria-label` cannot substitute for.
61
+
62
+ Also exported on the `./qr-code` subpath, and **the encoder is exported
63
+ separately** (`encodeQr`, `selectMode`) for a consumer that needs the modules
64
+ rather than an SVG — a canvas, a PDF, a thermal printer, a terminal. Without
65
+ that, getting at them would mean adding a dependency for something already in
66
+ the package.
67
+
68
+ Three notes that decide whether a code actually scans, none of which are
69
+ visible in a screenshot:
70
+
71
+ - **The quiet zone is not padding.** It is how a scanner finds the symbol's
72
+ edge, so it defaults to the standard's minimum of 4 modules. `quietZone={0}`
73
+ is allowed and is not a space saving.
74
+ - **`background` defaults to `"transparent"`**, which inherits whatever is
75
+ behind it — so on a dark surface the symbol renders dark-on-dark and most
76
+ scanners refuse it. Set `foreground` and `background` together there.
77
+ - **`"H"` is not a free upgrade over `"M"`.** It survives more damage and
78
+ holds a third less, so at the same pixel width the modules are smaller; on a
79
+ phone screen it can read *worse*. Raise it for print or a covered symbol.
80
+
81
+ Rendered as a single `<path>` on a module-unit `viewBox` rather than a `<rect>`
82
+ per module: a version 10 symbol has over three thousand modules, and the
83
+ module-unit viewBox is what lets `size` scale with no resampling — a raster
84
+ code at a non-integer multiple of its module size has blurred module edges,
85
+ and a scanner reading a blurred edge guesses.
86
+
87
+ `encodeQr` throws a `RangeError` rather than truncating a value that will not
88
+ fit, because a truncated symbol scans cleanly and yields the wrong string.
89
+ Kanji mode and structured append are not supported; an untested branch in an
90
+ encoder fails as a code a phone quietly refuses to read.
91
+
92
+ Built for `claude · tynn`'s device-pairing panel (Genie 2 §6.8), which
93
+ previously had only a typed URL.
94
+
14
95
  ## [5.35.1] - 2026-10-10
15
96
 
16
97
  ### Fixed