@faqir-ui/core 1.1.2 → 1.2.0

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.
Files changed (43) hide show
  1. package/README.md +9 -8
  2. package/cdn.json +40 -35
  3. package/dist/faqir-core.js +74 -68
  4. package/dist/faqir-core.min.js +3 -3
  5. package/dist/faqir-core.min.js.map +3 -3
  6. package/dist/faqir-core.mjs +134 -56
  7. package/dist/faqir.aurora.css +5013 -428
  8. package/dist/faqir.brutalist.css +5013 -428
  9. package/dist/faqir.candy.css +5013 -428
  10. package/dist/faqir.clay.css +19164 -0
  11. package/dist/faqir.clinical.css +5013 -428
  12. package/dist/faqir.contrast.css +5013 -428
  13. package/dist/faqir.deco.css +19247 -0
  14. package/dist/faqir.default.css +5013 -428
  15. package/dist/faqir.document-serif.css +5013 -428
  16. package/dist/faqir.document.css +5014 -428
  17. package/dist/faqir.editorial-document.css +5013 -428
  18. package/dist/faqir.editorial.css +5013 -428
  19. package/dist/faqir.fintech.css +5013 -428
  20. package/dist/faqir.glass.css +5013 -428
  21. package/dist/faqir.ink-document.css +5013 -428
  22. package/dist/faqir.ink.css +5013 -428
  23. package/dist/faqir.luxe.css +5013 -428
  24. package/dist/faqir.memphis.css +19163 -0
  25. package/dist/faqir.midnight.css +5013 -428
  26. package/dist/faqir.monolith.css +19162 -0
  27. package/dist/faqir.neo.css +5013 -428
  28. package/dist/faqir.neumorph.css +5013 -428
  29. package/dist/faqir.nordic.css +5013 -428
  30. package/dist/faqir.organic.css +5013 -428
  31. package/dist/faqir.paper.css +5013 -428
  32. package/dist/faqir.slate.css +5013 -428
  33. package/dist/faqir.soft.css +5013 -428
  34. package/dist/faqir.sunset.css +5013 -428
  35. package/dist/faqir.swiss-document.css +5013 -428
  36. package/dist/faqir.swiss.css +5013 -428
  37. package/dist/faqir.terminal.css +5013 -428
  38. package/dist/plugins/faqir-rules.js +1 -1
  39. package/dist/plugins/faqir-tweak.js +304 -0
  40. package/dist/plugins/faqir-validate.js +12 -4
  41. package/dist/sri.json +38 -33
  42. package/faqir-core.d.ts +42 -0
  43. package/package.json +1 -1
package/README.md CHANGED
@@ -12,10 +12,10 @@ any HTML file and you have a styled, interactive Faqir page. No build step, no i
12
12
 
13
13
  ```html
14
14
  <!-- 1. A theme's full CSS bundle (tokens + theme + base + every component) -->
15
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.1/dist/faqir.default.css">
15
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.2/dist/faqir.default.css">
16
16
 
17
17
  <!-- 2. The reactive engine — sets window.Faqir and auto-boots on DOMContentLoaded -->
18
- <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.1/dist/faqir-core.min.js" defer></script>
18
+ <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.2/dist/faqir-core.min.js" defer></script>
19
19
  ```
20
20
 
21
21
  That's it. Now write Faqir markup:
@@ -38,10 +38,10 @@ for tamper-proof loads:
38
38
 
39
39
  ```html
40
40
  <link rel="stylesheet"
41
- href="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.1/dist/faqir.default.css"
41
+ href="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.2/dist/faqir.default.css"
42
42
  integrity="sha384-…paste from sri.json…"
43
43
  crossorigin="anonymous">
44
- <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.1/dist/faqir-core.min.js"
44
+ <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.2/dist/faqir-core.min.js"
45
45
  integrity="sha384-…paste from sri.json…"
46
46
  crossorigin="anonymous" defer></script>
47
47
  ```
@@ -69,12 +69,13 @@ Each file in `dist/plugins/` is a self-registering classic script: load it
69
69
  | `faqir-mask.js` | `l-mask` | caret-safe input masking |
70
70
  | `faqir-persist.js` | `l-persist`, `$persist()` | localStorage-backed reactive state |
71
71
  | `faqir-rules.js` | `l-rules`, `$rules` | a form's conditional logic, from one JSON definition |
72
+ | `faqir-tweak.js` | `l-tweak`, `Faqir.tweak` | a live theme studio that writes tokens onto `<html>` and exports them |
72
73
  | `faqir-validate.js` | `l-validate` | declarative + programmatic form validation |
73
74
 
74
75
  ```html
75
- <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.1/dist/faqir-core.min.js" defer></script>
76
- <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.1/dist/plugins/faqir-validate.js" defer></script>
77
- <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.1/dist/plugins/faqir-rules.js" defer></script>
76
+ <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.2/dist/faqir-core.min.js" defer></script>
77
+ <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.2/dist/plugins/faqir-validate.js" defer></script>
78
+ <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.2/dist/plugins/faqir-rules.js" defer></script>
78
79
  ```
79
80
 
80
81
  One pairing to know: `faqir-rules` registers its cross-field and remote checks
@@ -87,7 +88,7 @@ Pin the plugin drops the same way as the engine — their hashes are in
87
88
  `dist/sri.json` beside the rest:
88
89
 
89
90
  ```html
90
- <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.1/dist/plugins/faqir-rules.js"
91
+ <script src="https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.2/dist/plugins/faqir-rules.js"
91
92
  integrity="sha384-…paste from sri.json…"
92
93
  crossorigin="anonymous" defer></script>
93
94
  ```
package/cdn.json CHANGED
@@ -1,44 +1,49 @@
1
1
  {
2
2
  "package": "@faqir-ui/core",
3
- "version": "1.1.2",
4
- "base": "https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.1.2/dist/",
3
+ "version": "1.2.0",
4
+ "base": "https://cdn.jsdelivr.net/npm/@faqir-ui/core@1.2.0/dist/",
5
5
  "integrity": {
6
- "faqir-core.js": "sha384-GHlaOUQ2hVOWHPv9DiXtyYgtCqdiwSB9LZ9gzvEcImqa8ISSkWprEfGjBpth/hK2",
7
- "faqir-core.min.js": "sha384-QIoNAZIvm+fow0p483t3dS7yjI/2mNpEfyg+xRq6mIKNJ0pbhTMDvS+RsXzWPXH+",
8
- "faqir-core.min.js.map": "sha384-D9M6vk5GQ302jHMYBA42YyBBAzoYFB14/Ai+4Q3SvYoHKaNnOwgVUCmY0udJee7l",
9
- "faqir-core.mjs": "sha384-NgEl5+je3pP718IFtOWR3i5nlcXmYOT2wVeY8yl5/03e1S6leM4kIIOXnewOgTqL",
10
- "faqir.aurora.css": "sha384-ZfycA0bNs1ZOLQFVAShto3TMcXm1ZkYd7HkENleFW9UHWAmM0rYFmAsDlRcbpD1P",
11
- "faqir.brutalist.css": "sha384-rKEWQ1ocsmIa4hFZrqSyZwADRrt2zlp+xvEeSjXgTlSq+xbODy16jyj0TThiRRIH",
12
- "faqir.candy.css": "sha384-9j6Hc3tfMFgU6AvZWLmXKXmWbe3UtYy4BPlfSCLWJ72OdhVzv/9uCVCsesXc3lll",
13
- "faqir.clinical.css": "sha384-fkMPP/oMpdji3Jbk4ZNAEwFCwxFVwcBSJm5xBmL8Fyw+XG5R9DG3jQdu7p3PwK2j",
14
- "faqir.contrast.css": "sha384-OHHowNIftVzWHlj6/4ps50ZHA6MJG6AkCxcixjZ63tkxCDpr83Wp7BLLbRJAb6ho",
15
- "faqir.default.css": "sha384-m9mJ/+g9iFEVKJCVE46Cfvmf21WKOOxjGKXwSAnUTacD6MKXMsZc9J+yWCyvWBNn",
16
- "faqir.document-serif.css": "sha384-g/vf0oMKMJNlxzcY2EMzou3EB5K6iN/09n6dbODX2ByMqZovShnKNynZVFdQzCE9",
17
- "faqir.document.css": "sha384-HINAn/RdXt2R48f7F44PZlhc1//xUew3qwL79YzJTsezdvePKQdFltQwOtyihUXu",
18
- "faqir.editorial-document.css": "sha384-7/lBHx0lZ9PJqB42PKKE55LtgXo682gOWgInWLgtIlUjoCzLR5/oTanZfGwd/Bch",
19
- "faqir.editorial.css": "sha384-uUiMtRova00e/GuBXW/N2uVY3l048tYj3bv+ga067W6ZvKwx4i8yULm6RbxB8wlo",
20
- "faqir.fintech.css": "sha384-OWyfsC3mjXV3OXWG2uo/vioWW9tnv8W+jDENq1XqC1Lj4Y02pRDfaB10kIQoWri6",
21
- "faqir.glass.css": "sha384-qkx/DVixf/A+8Cw7R7ADAKdyZnICWasgTMwmyEKNoI59AiGjRR6rr5+8IVmS+UMw",
22
- "faqir.ink-document.css": "sha384-a39pfAsSIa/wBMpwwF6kvZw6kWLc1qRHFcZefJCY2f49lpmeYzaEi2g9YVCwYc9V",
23
- "faqir.ink.css": "sha384-xWghw25FmwTdJKEyG76GUh/K7kuDMspbefBPUkfDUTcC9ZRdfMqRtbHLzTxo/ugb",
24
- "faqir.luxe.css": "sha384-EhVP+DEEzB9f7JenTo9G+1WdeLWUsEdYy59k4b/1uiP+/plnjr+TceCb4b+dkfGy",
25
- "faqir.midnight.css": "sha384-RpEh4Rhpw3ffsiV1Xy+S2ZhLhQMiwxnwHLwfB1vDwCSR7SlyoEQB/+sJNT5pgoC3",
26
- "faqir.neo.css": "sha384-peEZz+vAHXoXmmTZbFTcBKQka7IZAe2HnyBDDLXyTjSsGPZ7AMYVYzvaa9O9XfVF",
27
- "faqir.neumorph.css": "sha384-XjnfiTcYKSOS6QGxXXhlWjgxwsc2IK/uMRrB9JxiV9bxKNV19aiHeTR4keBtnSuy",
28
- "faqir.nordic.css": "sha384-ia8Jun21Bvz26UJkbnus0saxO2/Pxh/C+OStv07uFe029z8Ma9aEjFqXG9XQNazF",
29
- "faqir.organic.css": "sha384-uNmSZ1VJwDxC9hh7NnwDy5sUYEx7CFZdPQDmpebO5SVDOhIPJyo9baRc4+4tD4sa",
30
- "faqir.paper.css": "sha384-v19qP8TYy5uqAGiFTb0lLnpId68wYMGYNKalvZ+sKVL836TQC3ZC8k2LTvFVfX3n",
31
- "faqir.slate.css": "sha384-XfZ4IWpVS7+6m6ZqU3nEsNveg7X7WU5s9yOU+tkTkV6ALMohiG9u+zhCSkWuLCBJ",
32
- "faqir.soft.css": "sha384-YZ8hVr92Fbfdnve44ue2RvojtgPyJcdzO55vMnCo7aH5WtnznV6SRIl3/p+Pypk5",
33
- "faqir.sunset.css": "sha384-h2Ovn9eS+QCl24cojeI8LNjWk1uIsB3pjdyVxOz8KizMXQltFm3B9Y/rGL3OLx71",
34
- "faqir.swiss-document.css": "sha384-ujQOm08Wdiy3TW2HNrf4dpBH5nwXjqgWJGPEPMXr6zZ4ihu6udkAroXjuTQyJhJc",
35
- "faqir.swiss.css": "sha384-4C8wATYMgbyNm4wjsaxgqqtVEpMQI4EyAfsNBVFwB8GuNkMrsrhMIP0rpRWBYhJ4",
36
- "faqir.terminal.css": "sha384-fcEM0/i8MaY7XKf5Bhqt8cELiuJwCn8pwFX/tYPhDstOYzii4msJxufh9xFpk4zX",
6
+ "faqir-core.js": "sha384-oSPiZQb5mIYtZmrsnNSo8k+hPR5Vtj+vRBhyzNozUvPreSMCtlFAbpN1yC6h6Uxh",
7
+ "faqir-core.min.js": "sha384-Y/ObjBaUa4Ex33uNV5X++IK1pNAbYjGKYgPKfqHcjuL4xBb2At005nebcWxtkh/s",
8
+ "faqir-core.min.js.map": "sha384-BIOKuESd9GUiom8bpxYvxVJX7JnTzOmUG9vZpFUWEStCmZItzqvoyYxzLTHimjcT",
9
+ "faqir-core.mjs": "sha384-UDfHzfCPD8MgedS3Lh5vgtD3G7q+f3gtC402jFEb17qOkdZdxmikvriRhWFM2WqD",
10
+ "faqir.aurora.css": "sha384-O7Wv2oLKBqIIa2fFLZtmIeDTfVRIY7xahud1ANigc9GrwuXWC8S5mgq+49dTbcjm",
11
+ "faqir.brutalist.css": "sha384-hKZywJEhj3gZMRrUKzpDzPDe8SbUfT65XTCMr73jwqk36wYcFH61RlmlXtnecdoz",
12
+ "faqir.candy.css": "sha384-dCgK+o1yNlP8V+ZKU4Bd0AkVwOdX3834QdyX1q77cI2HwPECGio9E+JFE6fe2zPO",
13
+ "faqir.clay.css": "sha384-kMWNTs1EyXt8mGO0jCDRQATe3RtoE+ib2nTlA4I9dEfKrm/wRXEB/EOmBflmYeZV",
14
+ "faqir.clinical.css": "sha384-MUphY05uuN+f06x8uE3SSDa1OB09VwoDtz2VtGf7jzaROYMIwavQ6QyJF59QG6cu",
15
+ "faqir.contrast.css": "sha384-tDWLh2dEAEilGupWHgXCWqT7nSWUqjw9jCKhjwZNizBgSUSvv2n8qw2WbY6quIXm",
16
+ "faqir.deco.css": "sha384-iMIsXH+vKkvn371uVOkeLI/8GlBOzbWgp3ZbypZZBPh2Sx72hOwEsxYFKqsfEnDt",
17
+ "faqir.default.css": "sha384-uEZhIJiJ3OqaxWWs9bQYa8WXwVi6h5NCzpGghGrKfL9fHgwz5EM+8V+HNFIcbBn3",
18
+ "faqir.document-serif.css": "sha384-G1fXY22VtWhZU7OFgjoYAHKRHsrRrgsNK/Q9ujFZ6QEXPIUWmxGxmdqWwt77Sp9X",
19
+ "faqir.document.css": "sha384-uFsIc0MPqiYO5M3IEVuA9/d8Fie9bovzNPEurO2WfoWxaRDaPU+OX1DvSTdJlznj",
20
+ "faqir.editorial-document.css": "sha384-6bwR/CcUYm9+EfleRr1575dUDam5j+42n2oFLBOHsriRshRjFqu7RhFeUqh+qz18",
21
+ "faqir.editorial.css": "sha384-MNXkBiePIc8/vz6uRHXBrQXpUnsaAKj9ewRTtKgn3NsJVQteqIdFd+iRDk85UXum",
22
+ "faqir.fintech.css": "sha384-OeZiY4mj/BTS5UOSkUO8N09wJnA647RPTNMn4xAUONSMQaM5hmz39OpSK+CZTS8t",
23
+ "faqir.glass.css": "sha384-XxsAsrZsI7bSoiXY0M69nHODL9RXLsypPiQRNi/a3t7mPgRlrfpVeF1XqazySwIZ",
24
+ "faqir.ink-document.css": "sha384-ckm9FvqPBGKYH0a/YjS5/VEb0wzIDwQZ2nUexPw/tVMJmfdUA7Fv9mYHBAMfcAmm",
25
+ "faqir.ink.css": "sha384-1+0kDzO3g/8DJVJRnfbyYiFTkDkLFub31wDUXQOpyATkYlaRXuAqGUOickpnZDHI",
26
+ "faqir.luxe.css": "sha384-VECuRGQVX5tAPf9f4nlMLVbRt1D8QfSXIjLJymL0+3Xg5ciIt+JFTF54x5CEDtvC",
27
+ "faqir.memphis.css": "sha384-Ys0NhabYE9eJvtwpHXlvDy+zZYijrNSaWKysnf/O6lF9ZgcrGdeQ217UJv6vp8KN",
28
+ "faqir.midnight.css": "sha384-53kut5yzw/uUdx94tPiwQs7AuoXUm3WtFfubo1OqnDlleXUU1XFDNAAVt3B20J0m",
29
+ "faqir.monolith.css": "sha384-W5wiFpYP6jpmGJO+aJqGhZm/0UmISNpDnQIP5Nlz0UJqtNCVGf+b9Ss6AvPXRMRY",
30
+ "faqir.neo.css": "sha384-oFh/li8+nfUeNvFKEdjdU0enGCpy1oPbVQHnNBjBqxecjNdOn27dkGvSxSlvCb97",
31
+ "faqir.neumorph.css": "sha384-T+bc0+8l1Glcxzyg2BGoyFsYv1VGGS6LOklborctelrraugVpVVB2kUH+lrRFLhP",
32
+ "faqir.nordic.css": "sha384-YxRFYTXk8p3P/DkQK/qmIYT1djJLGPGWFLTHM4fpUeb5T+4eS3GpdDC5iNR7E5Y2",
33
+ "faqir.organic.css": "sha384-jInVyUMGkfiUGCUnNVtTcSWkIE9+gKD1Bro/B0BCaoDxz5lpUu7+oMT5DwYEwV6x",
34
+ "faqir.paper.css": "sha384-PX1BVPl7/KuVDuQwCQxr4sF+NewTOVfle9bZ84UXecZAe3hIaJk0z/Mt02Wt80MD",
35
+ "faqir.slate.css": "sha384-H3tEPGyt/rO6IjWLRh1AasgdJtMZoBiMG7Z6xy77TQWIDsOSvHUp6m5kOMGm380E",
36
+ "faqir.soft.css": "sha384-/h4lb3FiDm1xsf4lzq7Bo46QTKPCR80dXmThK57MAHHPSl9vjExdNeKWCJuHc8x+",
37
+ "faqir.sunset.css": "sha384-Q6HwuPDyuUm8zy1Q3oGSntM/5ShrwgYOlfzy9eTaGmpOhQezs/rM8018TDgqlzYD",
38
+ "faqir.swiss-document.css": "sha384-ZnsDSmgRCib00+CLAMtWE5dAvqp+K9jusr84CEMQe4u60EIOQrjetz1Px2f6TloS",
39
+ "faqir.swiss.css": "sha384-e9szmB9PrfXFylpwBcLafOJ9pO+L/T25Cr5B27AHXNEB4o4MZVlhfGLUMyXIh/He",
40
+ "faqir.terminal.css": "sha384-eVzvXojjoNdeCiLLT8SFKR6VHR9tgEJeqWNxEcbshKHrsy4oxqpititV7Rv0pbhp",
37
41
  "plugins/faqir-collapse.js": "sha384-3l5Z+isXlDkidRevDGkuNOiDp6eJ2ML11RkXA0j4ixQBaepuu8pAhyY4YRnR1qB7",
38
42
  "plugins/faqir-intersect.js": "sha384-Q/akZjAcnTnGYPKBP7b8c3iyYbHTIW1IPjBivzOH9dE7Nflr9Cu6adjeDXU2bhk6",
39
43
  "plugins/faqir-mask.js": "sha384-QvmZoq/+9/ef3U9JkdKlRMFhUMNGjnKct4JC3g7/ypEXEuTeny3JlUvsnrFv75v+",
40
44
  "plugins/faqir-persist.js": "sha384-o0jfddebC8QZ3S26VXUlOme723BNMlb/N7vqpn+fWpSeEFXzpq+3MoeXhVL/0PSv",
41
- "plugins/faqir-rules.js": "sha384-xJ/JhLJ+0oryaniOzZISjeDFAgiJfFwlUw+wCrLdmpr8m0ZAtN4rsvqD/1gwl/T/",
42
- "plugins/faqir-validate.js": "sha384-TIyGNL8dHBnFdV56LAhdklvhQLsClQqGuQ7DT0Zgxva8DIzfONXZSJYTXhQxJcN0"
45
+ "plugins/faqir-rules.js": "sha384-4P6QegEl5xANFU63W5O6J9qHNVZd2YYmSK+Fvj97LtHCOW8Zw9mskXbzw3vfJBmW",
46
+ "plugins/faqir-tweak.js": "sha384-hrasWR6y1Qwn7ktBPOPjuVPqam95j4YlhwGWVnbevkLdH7kklfVIUOjIpmibEcdE",
47
+ "plugins/faqir-validate.js": "sha384-f0J87Wkiuei3MJ6WmNUdje/Uc/LnLXdOGUtoUHfvT73XawsUfKLtniOE/qCjYpXD"
43
48
  }
44
49
  }
@@ -10,7 +10,7 @@
10
10
  // PRODUCTION BUILD — dev-only diagnostics stripped at assembly time.
11
11
  // Load faqir-core.dev.js instead while developing for full warnings.
12
12
  // Regenerate with: bun run build:core
13
- // Package version: 1.1.2
13
+ // Package version: 1.2.0
14
14
  // ============================================================================
15
15
 
16
16
  /**
@@ -541,8 +541,10 @@
541
541
  for (var i = 0; i < children.length; i++) {
542
542
  var child = children[i];
543
543
 
544
- // Skip elements already initialized by l-for or l-if
545
- if (child.__faqirScope && !child.hasAttribute('l-data')) {
544
+ // Skip elements already initialized by l-for or l-if — or teleported here
545
+ // by an earlier sibling's l-teleport, which bound them (and, with an
546
+ // l-data of their own, scoped them) on the way out.
547
+ if (child.__faqirStray || (child.__faqirScope && !child.hasAttribute('l-data'))) {
546
548
  continue;
547
549
  }
548
550
 
@@ -1522,7 +1524,7 @@
1522
1524
 
1523
1525
  // Named presets shipped by motion-presets.css. Unknown names still animate
1524
1526
  // (the attribute is stamped) but have no styling, so we warn to catch typos.
1525
- var MOTION_PRESETS = { fade: 1, 'slide-up': 1, scale: 1 };
1527
+ var MOTION_PRESETS = { fade: 1, 'slide-up': 1, 'slide-down': 1, 'slide-start': 1, 'slide-end': 1, scale: 1, blur: 1, flip: 1 };
1526
1528
 
1527
1529
  function prefersReducedMotion() {
1528
1530
  return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
@@ -1576,7 +1578,7 @@
1576
1578
  var preset = el.getAttribute('l-transition') || 'fade';
1577
1579
  if (!MOTION_PRESETS[preset]) {
1578
1580
  console.warn('[Faqir] l-transition: unknown preset "' + preset +
1579
- '" — expected one of: fade, slide-up, scale');
1581
+ '" — expected one of: ' + Object.keys(MOTION_PRESETS).join(', '));
1580
1582
  }
1581
1583
 
1582
1584
  el.setAttribute('data-motion', phase); // from-state (no transition yet)
@@ -1657,8 +1659,9 @@
1657
1659
  el.dataset.state = value ? 'on' : 'off';
1658
1660
  el.setAttribute('aria-checked', value ? 'true' : 'false');
1659
1661
  });
1660
- bind('change', function() {
1661
- writeModel(prop, el.checked, scope, el);
1662
+ // A switch is a <button role="switch">: no `checked`, and no `change`.
1663
+ bind('click', function() {
1664
+ writeModel(prop, !evaluate(prop, scope, el), scope, el);
1662
1665
  });
1663
1666
  addCleanup(el, cl);
1664
1667
 
@@ -6363,41 +6366,37 @@ function rsEncode(data, ecLen) {
6363
6366
 
6364
6367
  const ECL_MAP = { L: 0, M: 1, Q: 2, H: 3 };
6365
6368
 
6366
- // [version][ecl] → { totalBytes, ecPerBlock, blocks }
6367
- const VERSION_TABLE = [
6368
- null, // index 0 unused
6369
- // v1
6370
- [{ dc: 19, ec: 7, b: 1 }, { dc: 16, ec: 10, b: 1 }, { dc: 13, ec: 13, b: 1 }, { dc: 9, ec: 17, b: 1 }],
6371
- // v2
6372
- [{ dc: 34, ec: 10, b: 1 }, { dc: 28, ec: 16, b: 1 }, { dc: 22, ec: 22, b: 1 }, { dc: 16, ec: 28, b: 1 }],
6373
- // v3
6374
- [{ dc: 55, ec: 15, b: 1 }, { dc: 44, ec: 26, b: 1 }, { dc: 34, ec: 18, b: 2 }, { dc: 26, ec: 22, b: 2 }],
6375
- // v4
6376
- [{ dc: 80, ec: 20, b: 1 }, { dc: 64, ec: 18, b: 2 }, { dc: 48, ec: 26, b: 2 }, { dc: 36, ec: 16, b: 4 }],
6377
- // v5
6378
- [{ dc: 108, ec: 26, b: 1 }, { dc: 86, ec: 24, b: 2 }, { dc: 62, ec: 18, b: 4 }, { dc: 46, ec: 22, b: 4 }],
6379
- // v6
6380
- [{ dc: 136, ec: 18, b: 2 }, { dc: 108, ec: 16, b: 4 }, { dc: 76, ec: 24, b: 4 }, { dc: 60, ec: 28, b: 4 }],
6381
- // v7
6382
- [{ dc: 156, ec: 20, b: 2 }, { dc: 124, ec: 18, b: 4 }, { dc: 88, ec: 18, b: 6 }, { dc: 66, ec: 26, b: 5 }],
6383
- // v8
6384
- [{ dc: 194, ec: 24, b: 2 }, { dc: 154, ec: 22, b: 4 }, { dc: 110, ec: 22, b: 6 }, { dc: 86, ec: 26, b: 6 }],
6385
- // v9
6386
- [{ dc: 232, ec: 30, b: 2 }, { dc: 182, ec: 22, b: 5 }, { dc: 132, ec: 20, b: 8 }, { dc: 98, ec: 24, b: 8 }],
6387
- // v10
6388
- [{ dc: 274, ec: 18, b: 4 }, { dc: 216, ec: 26, b: 5 }, { dc: 154, ec: 24, b: 8 }, { dc: 119, ec: 28, b: 8 }],
6369
+ // ISO/IEC 18004 Table 9, flattened as [(version - 1) * 4 + ecl]: EC codewords
6370
+ // per block, and the block count. Data codewords are what is left of the
6371
+ // version's total once the EC blocks are taken out.
6372
+ const EC_PER_BLOCK = [
6373
+ 7, 10, 13, 17, 10, 16, 22, 28, 15, 26, 18, 22, 20, 18, 26, 16, 26, 24, 18, 22,
6374
+ 18, 16, 24, 28, 20, 18, 18, 26, 24, 22, 22, 26, 30, 22, 20, 24, 18, 26, 24, 28,
6389
6375
  ];
6390
-
6391
- const ALIGNMENT_POSITIONS = [
6392
- null, [], [6, 18], [6, 22], [6, 26], [6, 30],
6393
- [6, 34], [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50],
6376
+ const BLOCKS = [
6377
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 4, 1, 2, 4, 4,
6378
+ 2, 4, 4, 4, 2, 4, 6, 5, 2, 4, 6, 6, 2, 5, 8, 8, 4, 5, 8, 8,
6394
6379
  ];
6380
+ const TOTAL_CODEWORDS = [26, 44, 70, 100, 134, 172, 196, 242, 292, 346];
6381
+
6382
+ function versionInfo(version, eclIdx) {
6383
+ const i = (version - 1) * 4 + eclIdx;
6384
+ const ec = EC_PER_BLOCK[i];
6385
+ const b = BLOCKS[i];
6386
+ return { dc: TOTAL_CODEWORDS[version - 1] - ec * b, ec, b };
6387
+ }
6388
+
6389
+ // Alignment centres: none for v1, two up to v6, three from v7 (evenly spaced).
6390
+ function alignmentPositions(v) {
6391
+ return v < 2 ? [] : v < 7 ? [6, 4 * v + 10] : [6, 2 * v + 8, 4 * v + 10];
6392
+ }
6395
6393
 
6396
6394
  function selectVersion(dataLen, ecl) {
6397
6395
  const eclIdx = ECL_MAP[ecl] ?? 1;
6398
6396
  for (let v = 1; v <= 10; v++) {
6399
- const info = VERSION_TABLE[v][eclIdx];
6400
- if (dataLen <= info.dc) return v;
6397
+ const info = versionInfo(v, eclIdx);
6398
+ // + 4-bit mode and 8-bit (v1–9) or 16-bit (v10) character count, rounded up.
6399
+ if (dataLen + (v < 10 ? 2 : 3) <= info.dc) return v;
6401
6400
  }
6402
6401
  return -1;
6403
6402
  }
@@ -6416,16 +6415,14 @@ function setModule(matrix, row, col, val, reserved) {
6416
6415
  }
6417
6416
  }
6418
6417
 
6418
+ // Both patterns are concentric squares, coloured by their ring (Chebyshev
6419
+ // distance from the centre): a finder is dark at rings 0, 1 and 3, light at 2 and
6420
+ // at its ring-4 separator; an alignment pattern is dark at 0 and 2, light at 1.
6419
6421
  function placeFinderPattern(matrix, reserved, row, col) {
6420
6422
  for (let r = -1; r <= 7; r++) {
6421
6423
  for (let c = -1; c <= 7; c++) {
6422
- const val =
6423
- (r >= 0 && r <= 6 && (c === 0 || c === 6)) ||
6424
- (c >= 0 && c <= 6 && (r === 0 || r === 6)) ||
6425
- (r >= 2 && r <= 4 && c >= 2 && c <= 4)
6426
- ? 1
6427
- : 0;
6428
- setModule(matrix, row + r, col + c, val, reserved);
6424
+ const d = Math.max(Math.abs(r - 3), Math.abs(c - 3));
6425
+ setModule(matrix, row + r, col + c, d !== 2 && d !== 4 ? 1 : 0, reserved);
6429
6426
  }
6430
6427
  }
6431
6428
  }
@@ -6433,9 +6430,8 @@ function placeFinderPattern(matrix, reserved, row, col) {
6433
6430
  function placeAlignmentPattern(matrix, reserved, row, col) {
6434
6431
  for (let r = -2; r <= 2; r++) {
6435
6432
  for (let c = -2; c <= 2; c++) {
6436
- const val =
6437
- Math.abs(r) === 2 || Math.abs(c) === 2 || (r === 0 && c === 0) ? 1 : 0;
6438
- setModule(matrix, row + r, col + c, val, reserved);
6433
+ const d = Math.max(Math.abs(r), Math.abs(c));
6434
+ setModule(matrix, row + r, col + c, d !== 1 ? 1 : 0, reserved);
6439
6435
  }
6440
6436
  }
6441
6437
  }
@@ -6461,23 +6457,34 @@ function reserveFormatArea(matrix, reserved) {
6461
6457
  setModule(matrix, s - 8, 8, 1, reserved); // dark module
6462
6458
  }
6463
6459
 
6460
+ // Versions 7+ carry an 18-bit version word (BCH 18,6) in two 6×3 blocks.
6461
+ function placeVersionInfo(matrix, reserved, version) {
6462
+ if (version < 7) return;
6463
+ const s = matrix.length;
6464
+ let rem = version;
6465
+ for (let i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >> 11) * 0x1f25);
6466
+ const bits = (version << 12) | rem;
6467
+ for (let i = 0; i < 18; i++) {
6468
+ const bit = (bits >> i) & 1;
6469
+ const a = s - 11 + (i % 3);
6470
+ const b = (i / 3) | 0;
6471
+ setModule(matrix, b, a, bit, reserved);
6472
+ setModule(matrix, a, b, bit, reserved);
6473
+ }
6474
+ }
6475
+
6464
6476
  function placeData(matrix, reserved, bits) {
6465
6477
  const s = matrix.length;
6466
6478
  let bitIdx = 0;
6467
- let upward = true;
6468
- for (let col = s - 1; col >= 1; col -= 2) {
6479
+ for (let col = s - 1, upward = true; col >= 1; col -= 2, upward = !upward) {
6469
6480
  if (col === 6) col = 5; // skip timing column
6470
- const rows = upward
6471
- ? Array.from({ length: s }, (_, i) => s - 1 - i)
6472
- : Array.from({ length: s }, (_, i) => i);
6473
- for (const row of rows) {
6474
- for (let c = 0; c < 2; c++) {
6475
- const cc = col - c;
6476
- if (reserved[row][cc]) continue;
6477
- matrix[row][cc] = bitIdx < bits.length ? bits[bitIdx++] : 0;
6481
+ for (let i = 0; i < s; i++) {
6482
+ const row = upward ? s - 1 - i : i;
6483
+ for (let cc = col; cc > col - 2; cc--) {
6484
+ // Past the last bit the remainder modules are 0.
6485
+ if (!reserved[row][cc]) matrix[row][cc] = bits[bitIdx++] | 0;
6478
6486
  }
6479
6487
  }
6480
- upward = !upward;
6481
6488
  }
6482
6489
  }
6483
6490
 
@@ -6519,8 +6526,9 @@ function placeFormatInfo(matrix, ecl, maskId) {
6519
6526
  else if (i === 7) matrix[8][8] = bit;
6520
6527
  else if (i === 8) matrix[7][8] = bit;
6521
6528
  else matrix[14 - i][8] = bit;
6522
- // Around other finders
6523
- if (i < 8) matrix[s - 1 - i][8] = bit;
6529
+ // The second copy: bits 0–6 up column 8 from the bottom, 7–14 along row 8
6530
+ // to the right edge. (s - 8, 8) between them is the always-dark module.
6531
+ if (i < 7) matrix[s - 1 - i][8] = bit;
6524
6532
  else matrix[8][s - 15 + i] = bit;
6525
6533
  }
6526
6534
  }
@@ -6562,7 +6570,7 @@ function encodeQR(text, ecl = "M") {
6562
6570
  if (version < 0) throw new Error("Data too long for QR versions 1–10");
6563
6571
 
6564
6572
  const eclIdx = ECL_MAP[ecl] ?? 1;
6565
- const info = VERSION_TABLE[version][eclIdx];
6573
+ const info = versionInfo(version, eclIdx);
6566
6574
  const size = version * 4 + 17;
6567
6575
 
6568
6576
  // Build data codewords
@@ -6602,7 +6610,6 @@ function encodeQR(text, ecl = "M") {
6602
6610
  // Split into blocks and compute EC
6603
6611
  const blocks = [];
6604
6612
  const ecBlocks = [];
6605
- const ecPerBlock = info.ec / info.b;
6606
6613
  const dcPerBlock = Math.floor(info.dc / info.b);
6607
6614
  const remainder = info.dc % info.b;
6608
6615
  let offset = 0;
@@ -6612,7 +6619,7 @@ function encodeQR(text, ecl = "M") {
6612
6619
  const blockData = codewords.slice(offset, offset + blockDc);
6613
6620
  offset += blockDc;
6614
6621
  blocks.push(blockData);
6615
- ecBlocks.push(rsEncode(blockData, ecPerBlock));
6622
+ ecBlocks.push(rsEncode(blockData, info.ec));
6616
6623
  }
6617
6624
 
6618
6625
  // Interleave
@@ -6623,10 +6630,8 @@ function encodeQR(text, ecl = "M") {
6623
6630
  if (i < block.length) interleaved.push(block[i]);
6624
6631
  }
6625
6632
  }
6626
- for (let i = 0; i < ecPerBlock; i++) {
6627
- for (const ec of ecBlocks) {
6628
- if (i < ec.length) interleaved.push(ec[i]);
6629
- }
6633
+ for (let i = 0; i < info.ec; i++) {
6634
+ for (const ec of ecBlocks) interleaved.push(ec[i]);
6630
6635
  }
6631
6636
 
6632
6637
  // Convert to bit array
@@ -6643,7 +6648,7 @@ function encodeQR(text, ecl = "M") {
6643
6648
  placeFinderPattern(matrix, reserved, 0, size - 7);
6644
6649
  placeFinderPattern(matrix, reserved, size - 7, 0);
6645
6650
 
6646
- const alignPos = ALIGNMENT_POSITIONS[version] || [];
6651
+ const alignPos = alignmentPositions(version);
6647
6652
  for (const r of alignPos) {
6648
6653
  for (const c of alignPos) {
6649
6654
  if (reserved[r]?.[c]) continue;
@@ -6653,6 +6658,7 @@ function encodeQR(text, ecl = "M") {
6653
6658
 
6654
6659
  placeTimingPatterns(matrix, reserved);
6655
6660
  reserveFormatArea(matrix, reserved);
6661
+ placeVersionInfo(matrix, reserved, version);
6656
6662
 
6657
6663
  // Try all masks, pick lowest penalty
6658
6664
  let bestMask = 0;
@@ -11979,7 +11985,7 @@ function createTreeView(root) {
11979
11985
  // one time it was hand-maintained (0.1.0 in a package versioned 0.2.4), so
11980
11986
  // the built artifact is now the only place the number is authoritative and
11981
11987
  // the build fails if this marker goes missing.
11982
- version: '1.1.2', // @faqir:version
11988
+ version: '1.2.0', // @faqir:version
11983
11989
  reactive: reactive,
11984
11990
  effect: effect,
11985
11991
  batch: batch,