tempest-react-sdk 0.77.0 → 0.79.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 (1623) hide show
  1. package/README.md +6 -6
  2. package/bin/lib/alias/collect.mjs +20 -3
  3. package/bin/lib/alias/index.mjs +12 -1
  4. package/bin/lib/alias/index.test.mjs +24 -0
  5. package/bin/lib/css/analyze.test.mjs +21 -1
  6. package/bin/lib/css/collect.mjs +14 -0
  7. package/bin/lib/css/extract.mjs +63 -5
  8. package/bin/lib/css/extract.test.mjs +110 -1
  9. package/bin/lib/css/fix.e2e.test.mjs +50 -0
  10. package/bin/lib/css/index.mjs +6 -1
  11. package/bin/lib/fs/contain.mjs +50 -0
  12. package/bin/lib/icons/generate.mjs +28 -3
  13. package/bin/lib/icons/generate.test.mjs +57 -1
  14. package/bin/lib/openapi/escape.mjs +20 -6
  15. package/bin/lib/openapi/generate.encode.test.mjs +120 -0
  16. package/bin/lib/openapi/generate.hostile.test.mjs +38 -9
  17. package/bin/lib/openapi/generate.mjs +203 -64
  18. package/bin/lib/openapi/generate.pagination.test.mjs +3 -2
  19. package/bin/lib/openapi/generate.test.mjs +270 -3
  20. package/bin/lib/openapi/schema-to-zod.mjs +5 -3
  21. package/bin/tempest-gen.test.mjs +188 -0
  22. package/bin/tempest.mjs +120 -44
  23. package/dist/access/Can.cjs.map +1 -1
  24. package/dist/access/Can.js.map +1 -1
  25. package/dist/access/access-control-context.cjs.map +1 -1
  26. package/dist/access/access-control-context.js.map +1 -1
  27. package/dist/access/create-role-access-control.cjs.map +1 -1
  28. package/dist/access/create-role-access-control.js.map +1 -1
  29. package/dist/access/permissions-from-token.cjs.map +1 -1
  30. package/dist/access/permissions-from-token.js.map +1 -1
  31. package/dist/access/use-can.cjs.map +1 -1
  32. package/dist/access/use-can.js.map +1 -1
  33. package/dist/app/AppProviders.cjs.map +1 -1
  34. package/dist/app/AppProviders.js.map +1 -1
  35. package/dist/audio/audio-bus.cjs.map +1 -1
  36. package/dist/audio/audio-bus.js.map +1 -1
  37. package/dist/audio/audio-output.cjs.map +1 -1
  38. package/dist/audio/audio-output.js.map +1 -1
  39. package/dist/audio/audio-player.cjs.map +1 -1
  40. package/dist/audio/audio-player.js.map +1 -1
  41. package/dist/audio/audio-recorder.cjs.map +1 -1
  42. package/dist/audio/audio-recorder.js.map +1 -1
  43. package/dist/audio/duration.cjs.map +1 -1
  44. package/dist/audio/duration.js.map +1 -1
  45. package/dist/audio/level-meter.cjs.map +1 -1
  46. package/dist/audio/level-meter.js.map +1 -1
  47. package/dist/audio/media-access.cjs.map +1 -1
  48. package/dist/audio/media-access.js.map +1 -1
  49. package/dist/audio/noise-floor.cjs.map +1 -1
  50. package/dist/audio/noise-floor.js.map +1 -1
  51. package/dist/audio/sfx-pool.cjs.map +1 -1
  52. package/dist/audio/sfx-pool.js.map +1 -1
  53. package/dist/audio/use-audio-bus.cjs.map +1 -1
  54. package/dist/audio/use-audio-bus.js.map +1 -1
  55. package/dist/audio/use-audio-recorder.cjs.map +1 -1
  56. package/dist/audio/use-audio-recorder.js.map +1 -1
  57. package/dist/audio/use-audio.cjs.map +1 -1
  58. package/dist/audio/use-audio.js.map +1 -1
  59. package/dist/audio/use-microphone.cjs +1 -1
  60. package/dist/audio/use-microphone.cjs.map +1 -1
  61. package/dist/audio/use-microphone.js +1 -5
  62. package/dist/audio/use-microphone.js.map +1 -1
  63. package/dist/audio/use-sfx-pool.cjs.map +1 -1
  64. package/dist/audio/use-sfx-pool.js.map +1 -1
  65. package/dist/audio/voice-activity.cjs.map +1 -1
  66. package/dist/audio/voice-activity.js.map +1 -1
  67. package/dist/audio/voice-chain-stages.cjs.map +1 -1
  68. package/dist/audio/voice-chain-stages.js.map +1 -1
  69. package/dist/audio/voice-chain.cjs.map +1 -1
  70. package/dist/audio/voice-chain.js.map +1 -1
  71. package/dist/audio/wav.cjs.map +1 -1
  72. package/dist/audio/wav.js.map +1 -1
  73. package/dist/auth/AuthGuard.cjs.map +1 -1
  74. package/dist/auth/AuthGuard.js.map +1 -1
  75. package/dist/auth/create-auth-store.cjs.map +1 -1
  76. package/dist/auth/create-auth-store.js.map +1 -1
  77. package/dist/auth/create-tempest-auth.cjs +1 -1
  78. package/dist/auth/create-tempest-auth.cjs.map +1 -1
  79. package/dist/auth/create-tempest-auth.js +185 -114
  80. package/dist/auth/create-tempest-auth.js.map +1 -1
  81. package/dist/auth/jwt.cjs.map +1 -1
  82. package/dist/auth/jwt.js.map +1 -1
  83. package/dist/auth/lazy-with-retry.cjs.map +1 -1
  84. package/dist/auth/lazy-with-retry.js.map +1 -1
  85. package/dist/auth/passkey.cjs.map +1 -1
  86. package/dist/auth/passkey.js.map +1 -1
  87. package/dist/auth/refresh-queue.cjs.map +1 -1
  88. package/dist/auth/refresh-queue.js.map +1 -1
  89. package/dist/auth/use-passkey.cjs +1 -1
  90. package/dist/auth/use-passkey.cjs.map +1 -1
  91. package/dist/auth/use-passkey.js +1 -1
  92. package/dist/auth/use-passkey.js.map +1 -1
  93. package/dist/br/BrazilMap.cjs.map +1 -1
  94. package/dist/br/BrazilMap.js.map +1 -1
  95. package/dist/br/BrazilMap.module.cjs.map +1 -1
  96. package/dist/br/BrazilMap.module.js.map +1 -1
  97. package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
  98. package/dist/br/BrazilStateCitySelect.js.map +1 -1
  99. package/dist/br/BrazilStateMap.cjs.map +1 -1
  100. package/dist/br/BrazilStateMap.js.map +1 -1
  101. package/dist/br/MapLegend.cjs.map +1 -1
  102. package/dist/br/MapLegend.js.map +1 -1
  103. package/dist/br/MapLegend.module.cjs.map +1 -1
  104. package/dist/br/MapLegend.module.js.map +1 -1
  105. package/dist/br/MapMarkers.cjs.map +1 -1
  106. package/dist/br/MapMarkers.js.map +1 -1
  107. package/dist/br/MapTooltip.cjs.map +1 -1
  108. package/dist/br/MapTooltip.js.map +1 -1
  109. package/dist/br/MunicipalitySearch.cjs +1 -1
  110. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  111. package/dist/br/MunicipalitySearch.js +2 -5
  112. package/dist/br/MunicipalitySearch.js.map +1 -1
  113. package/dist/br/MunicipalitySearch.module.cjs.map +1 -1
  114. package/dist/br/MunicipalitySearch.module.js.map +1 -1
  115. package/dist/br/PixQRCode.cjs.map +1 -1
  116. package/dist/br/PixQRCode.js.map +1 -1
  117. package/dist/br/PixQRCode.module.cjs.map +1 -1
  118. package/dist/br/PixQRCode.module.js.map +1 -1
  119. package/dist/br/boleto.cjs.map +1 -1
  120. package/dist/br/boleto.js.map +1 -1
  121. package/dist/br/br-geo.cjs.map +1 -1
  122. package/dist/br/br-geo.js.map +1 -1
  123. package/dist/br/data/br-centroids.cjs.map +1 -1
  124. package/dist/br/data/br-centroids.js.map +1 -1
  125. package/dist/br/data/br-locations.cjs.map +1 -1
  126. package/dist/br/data/br-locations.js.map +1 -1
  127. package/dist/br/data/br-uf-geo.cjs.map +1 -1
  128. package/dist/br/data/br-uf-geo.js.map +1 -1
  129. package/dist/br/data/mun/AC.cjs.map +1 -1
  130. package/dist/br/data/mun/AC.js.map +1 -1
  131. package/dist/br/data/mun/AL.cjs.map +1 -1
  132. package/dist/br/data/mun/AL.js.map +1 -1
  133. package/dist/br/data/mun/AM.cjs.map +1 -1
  134. package/dist/br/data/mun/AM.js.map +1 -1
  135. package/dist/br/data/mun/AP.cjs.map +1 -1
  136. package/dist/br/data/mun/AP.js.map +1 -1
  137. package/dist/br/data/mun/BA.cjs.map +1 -1
  138. package/dist/br/data/mun/BA.js.map +1 -1
  139. package/dist/br/data/mun/CE.cjs.map +1 -1
  140. package/dist/br/data/mun/CE.js.map +1 -1
  141. package/dist/br/data/mun/DF.cjs.map +1 -1
  142. package/dist/br/data/mun/DF.js.map +1 -1
  143. package/dist/br/data/mun/ES.cjs.map +1 -1
  144. package/dist/br/data/mun/ES.js.map +1 -1
  145. package/dist/br/data/mun/GO.cjs.map +1 -1
  146. package/dist/br/data/mun/GO.js.map +1 -1
  147. package/dist/br/data/mun/MA.cjs.map +1 -1
  148. package/dist/br/data/mun/MA.js.map +1 -1
  149. package/dist/br/data/mun/MG.cjs.map +1 -1
  150. package/dist/br/data/mun/MG.js.map +1 -1
  151. package/dist/br/data/mun/MS.cjs.map +1 -1
  152. package/dist/br/data/mun/MS.js.map +1 -1
  153. package/dist/br/data/mun/MT.cjs.map +1 -1
  154. package/dist/br/data/mun/MT.js.map +1 -1
  155. package/dist/br/data/mun/PA.cjs.map +1 -1
  156. package/dist/br/data/mun/PA.js.map +1 -1
  157. package/dist/br/data/mun/PB.cjs.map +1 -1
  158. package/dist/br/data/mun/PB.js.map +1 -1
  159. package/dist/br/data/mun/PE.cjs.map +1 -1
  160. package/dist/br/data/mun/PE.js.map +1 -1
  161. package/dist/br/data/mun/PI.cjs.map +1 -1
  162. package/dist/br/data/mun/PI.js.map +1 -1
  163. package/dist/br/data/mun/PR.cjs.map +1 -1
  164. package/dist/br/data/mun/PR.js.map +1 -1
  165. package/dist/br/data/mun/RJ.cjs.map +1 -1
  166. package/dist/br/data/mun/RJ.js.map +1 -1
  167. package/dist/br/data/mun/RN.cjs.map +1 -1
  168. package/dist/br/data/mun/RN.js.map +1 -1
  169. package/dist/br/data/mun/RO.cjs.map +1 -1
  170. package/dist/br/data/mun/RO.js.map +1 -1
  171. package/dist/br/data/mun/RR.cjs.map +1 -1
  172. package/dist/br/data/mun/RR.js.map +1 -1
  173. package/dist/br/data/mun/RS.cjs.map +1 -1
  174. package/dist/br/data/mun/RS.js.map +1 -1
  175. package/dist/br/data/mun/SC.cjs.map +1 -1
  176. package/dist/br/data/mun/SC.js.map +1 -1
  177. package/dist/br/data/mun/SE.cjs.map +1 -1
  178. package/dist/br/data/mun/SE.js.map +1 -1
  179. package/dist/br/data/mun/SP.cjs.map +1 -1
  180. package/dist/br/data/mun/SP.js.map +1 -1
  181. package/dist/br/data/mun/TO.cjs.map +1 -1
  182. package/dist/br/data/mun/TO.js.map +1 -1
  183. package/dist/br/geocode.cjs.map +1 -1
  184. package/dist/br/geocode.js.map +1 -1
  185. package/dist/br/holidays.cjs.map +1 -1
  186. package/dist/br/holidays.js.map +1 -1
  187. package/dist/br/locations.cjs.map +1 -1
  188. package/dist/br/locations.js.map +1 -1
  189. package/dist/br/nfe.cjs.map +1 -1
  190. package/dist/br/nfe.js.map +1 -1
  191. package/dist/br/pix.cjs +1 -1
  192. package/dist/br/pix.cjs.map +1 -1
  193. package/dist/br/pix.js +108 -71
  194. package/dist/br/pix.js.map +1 -1
  195. package/dist/br/regions.cjs.map +1 -1
  196. package/dist/br/regions.js.map +1 -1
  197. package/dist/br/scales.cjs.map +1 -1
  198. package/dist/br/scales.js.map +1 -1
  199. package/dist/br/state-geo.cjs.map +1 -1
  200. package/dist/br/state-geo.js.map +1 -1
  201. package/dist/br/svg-utils.cjs.map +1 -1
  202. package/dist/br/svg-utils.js.map +1 -1
  203. package/dist/br/use-map-hover.cjs.map +1 -1
  204. package/dist/br/use-map-hover.js.map +1 -1
  205. package/dist/br/use-map-zoom.cjs.map +1 -1
  206. package/dist/br/use-map-zoom.js.map +1 -1
  207. package/dist/br/whatsapp.cjs.map +1 -1
  208. package/dist/br/whatsapp.js.map +1 -1
  209. package/dist/br.cjs.map +1 -1
  210. package/dist/br.d.ts +16 -5
  211. package/dist/br.js.map +1 -1
  212. package/dist/capture/barcode.cjs.map +1 -1
  213. package/dist/capture/barcode.js.map +1 -1
  214. package/dist/capture/media-recorder.cjs.map +1 -1
  215. package/dist/capture/media-recorder.js.map +1 -1
  216. package/dist/capture/use-barcode-scanner.cjs.map +1 -1
  217. package/dist/capture/use-barcode-scanner.js.map +1 -1
  218. package/dist/capture/use-screen-capture.cjs +1 -1
  219. package/dist/capture/use-screen-capture.cjs.map +1 -1
  220. package/dist/capture/use-screen-capture.js +1 -7
  221. package/dist/capture/use-screen-capture.js.map +1 -1
  222. package/dist/capture/use-speech-recognition.cjs +1 -1
  223. package/dist/capture/use-speech-recognition.cjs.map +1 -1
  224. package/dist/capture/use-speech-recognition.js +35 -36
  225. package/dist/capture/use-speech-recognition.js.map +1 -1
  226. package/dist/capture/use-torch.cjs.map +1 -1
  227. package/dist/capture/use-torch.js.map +1 -1
  228. package/dist/capture/use-video-recorder.cjs.map +1 -1
  229. package/dist/capture/use-video-recorder.js.map +1 -1
  230. package/dist/capture/video-recorder.cjs.map +1 -1
  231. package/dist/capture/video-recorder.js.map +1 -1
  232. package/dist/charts/AreaChart.cjs.map +1 -1
  233. package/dist/charts/AreaChart.js.map +1 -1
  234. package/dist/charts/BarChart.cjs.map +1 -1
  235. package/dist/charts/BarChart.js.map +1 -1
  236. package/dist/charts/LineChart.cjs.map +1 -1
  237. package/dist/charts/LineChart.js.map +1 -1
  238. package/dist/charts/PieChart.cjs.map +1 -1
  239. package/dist/charts/PieChart.js.map +1 -1
  240. package/dist/charts/RadarChart.cjs.map +1 -1
  241. package/dist/charts/RadarChart.js.map +1 -1
  242. package/dist/charts/palette.cjs.map +1 -1
  243. package/dist/charts/palette.js.map +1 -1
  244. package/dist/charts/scales.cjs.map +1 -1
  245. package/dist/charts/scales.js.map +1 -1
  246. package/dist/charts/types.cjs.map +1 -1
  247. package/dist/charts/types.js.map +1 -1
  248. package/dist/charts/use-chart-colors.cjs.map +1 -1
  249. package/dist/charts/use-chart-colors.js.map +1 -1
  250. package/dist/components/AIChat/AIChat.cjs +1 -1
  251. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  252. package/dist/components/AIChat/AIChat.js +1 -5
  253. package/dist/components/AIChat/AIChat.js.map +1 -1
  254. package/dist/components/AIChat/AIChat.module.cjs.map +1 -1
  255. package/dist/components/AIChat/AIChat.module.js.map +1 -1
  256. package/dist/components/AIChat/AIChatComposer.cjs +1 -1
  257. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  258. package/dist/components/AIChat/AIChatComposer.js +1 -7
  259. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  260. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  261. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  262. package/dist/components/AIChat/ai-chat-turns.cjs.map +1 -1
  263. package/dist/components/AIChat/ai-chat-turns.js.map +1 -1
  264. package/dist/components/Accordion/Accordion.cjs.map +1 -1
  265. package/dist/components/Accordion/Accordion.js.map +1 -1
  266. package/dist/components/Accordion/Accordion.module.cjs.map +1 -1
  267. package/dist/components/Accordion/Accordion.module.js.map +1 -1
  268. package/dist/components/Alert/Alert.cjs.map +1 -1
  269. package/dist/components/Alert/Alert.js.map +1 -1
  270. package/dist/components/Alert/Alert.module.cjs.map +1 -1
  271. package/dist/components/Alert/Alert.module.js.map +1 -1
  272. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  273. package/dist/components/AppBar/AppBar.js.map +1 -1
  274. package/dist/components/AppBar/AppBar.module.cjs.map +1 -1
  275. package/dist/components/AppBar/AppBar.module.js.map +1 -1
  276. package/dist/components/AppBar/use-sticky-body-warning.cjs +1 -1
  277. package/dist/components/AppBar/use-sticky-body-warning.cjs.map +1 -1
  278. package/dist/components/AppBar/use-sticky-body-warning.js +1 -1
  279. package/dist/components/AppBar/use-sticky-body-warning.js.map +1 -1
  280. package/dist/components/AppShell/AppShell.cjs.map +1 -1
  281. package/dist/components/AppShell/AppShell.js.map +1 -1
  282. package/dist/components/AppShell/AppShell.module.cjs.map +1 -1
  283. package/dist/components/AppShell/AppShell.module.js.map +1 -1
  284. package/dist/components/AspectRatio/AspectRatio.cjs.map +1 -1
  285. package/dist/components/AspectRatio/AspectRatio.js.map +1 -1
  286. package/dist/components/AspectRatio/AspectRatio.module.cjs.map +1 -1
  287. package/dist/components/AspectRatio/AspectRatio.module.js.map +1 -1
  288. package/dist/components/AudioPlayer/AudioPlayer.cjs +1 -1
  289. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
  290. package/dist/components/AudioPlayer/AudioPlayer.js +1 -7
  291. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
  292. package/dist/components/AudioPlayer/AudioPlayer.module.cjs.map +1 -1
  293. package/dist/components/AudioPlayer/AudioPlayer.module.js.map +1 -1
  294. package/dist/components/AudioRecorder/AudioRecorder.cjs +1 -1
  295. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
  296. package/dist/components/AudioRecorder/AudioRecorder.js +16 -21
  297. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
  298. package/dist/components/AudioRecorder/AudioRecorder.module.cjs.map +1 -1
  299. package/dist/components/AudioRecorder/AudioRecorder.module.js.map +1 -1
  300. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  301. package/dist/components/Avatar/Avatar.js.map +1 -1
  302. package/dist/components/Avatar/Avatar.module.cjs.map +1 -1
  303. package/dist/components/Avatar/Avatar.module.js.map +1 -1
  304. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
  305. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
  306. package/dist/components/AvatarGroup/AvatarGroup.module.cjs.map +1 -1
  307. package/dist/components/AvatarGroup/AvatarGroup.module.js.map +1 -1
  308. package/dist/components/Badge/Badge.cjs.map +1 -1
  309. package/dist/components/Badge/Badge.js.map +1 -1
  310. package/dist/components/Badge/Badge.module.cjs.map +1 -1
  311. package/dist/components/Badge/Badge.module.js.map +1 -1
  312. package/dist/components/Banner/Banner.cjs.map +1 -1
  313. package/dist/components/Banner/Banner.js.map +1 -1
  314. package/dist/components/Banner/Banner.module.cjs.map +1 -1
  315. package/dist/components/Banner/Banner.module.js.map +1 -1
  316. package/dist/components/BarList/BarList.cjs.map +1 -1
  317. package/dist/components/BarList/BarList.js.map +1 -1
  318. package/dist/components/BarList/BarList.module.cjs.map +1 -1
  319. package/dist/components/BarList/BarList.module.js.map +1 -1
  320. package/dist/components/BarList/bar-list-model.cjs.map +1 -1
  321. package/dist/components/BarList/bar-list-model.js.map +1 -1
  322. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
  323. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
  324. package/dist/components/BarcodeScanner/BarcodeScanner.module.cjs.map +1 -1
  325. package/dist/components/BarcodeScanner/BarcodeScanner.module.js.map +1 -1
  326. package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  327. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  328. package/dist/components/BottomNavigation/BottomNavigation.module.cjs.map +1 -1
  329. package/dist/components/BottomNavigation/BottomNavigation.module.js.map +1 -1
  330. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  331. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  332. package/dist/components/BottomSheet/BottomSheet.module.cjs.map +1 -1
  333. package/dist/components/BottomSheet/BottomSheet.module.js.map +1 -1
  334. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  335. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  336. package/dist/components/Breadcrumbs/Breadcrumbs.module.cjs.map +1 -1
  337. package/dist/components/Breadcrumbs/Breadcrumbs.module.js.map +1 -1
  338. package/dist/components/Button/Button.cjs.map +1 -1
  339. package/dist/components/Button/Button.js.map +1 -1
  340. package/dist/components/Button/Button.module.cjs.map +1 -1
  341. package/dist/components/Button/Button.module.js.map +1 -1
  342. package/dist/components/Button/ButtonContent.cjs.map +1 -1
  343. package/dist/components/Button/ButtonContent.js.map +1 -1
  344. package/dist/components/Button/ButtonSlot.cjs.map +1 -1
  345. package/dist/components/Button/ButtonSlot.js.map +1 -1
  346. package/dist/components/Button/button-class.cjs.map +1 -1
  347. package/dist/components/Button/button-class.js.map +1 -1
  348. package/dist/components/Button/link-rel.cjs.map +1 -1
  349. package/dist/components/Button/link-rel.js.map +1 -1
  350. package/dist/components/Button/slot.cjs.map +1 -1
  351. package/dist/components/Button/slot.js.map +1 -1
  352. package/dist/components/Calendar/Calendar.cjs.map +1 -1
  353. package/dist/components/Calendar/Calendar.js.map +1 -1
  354. package/dist/components/Calendar/Calendar.module.cjs.map +1 -1
  355. package/dist/components/Calendar/Calendar.module.js.map +1 -1
  356. package/dist/components/Card/Card.cjs.map +1 -1
  357. package/dist/components/Card/Card.js.map +1 -1
  358. package/dist/components/Card/Card.module.cjs.map +1 -1
  359. package/dist/components/Card/Card.module.js.map +1 -1
  360. package/dist/components/Carousel/Carousel.cjs.map +1 -1
  361. package/dist/components/Carousel/Carousel.js.map +1 -1
  362. package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
  363. package/dist/components/Carousel/Carousel.module.js.map +1 -1
  364. package/dist/components/Center/Center.cjs.map +1 -1
  365. package/dist/components/Center/Center.js.map +1 -1
  366. package/dist/components/Center/Center.module.cjs.map +1 -1
  367. package/dist/components/Center/Center.module.js.map +1 -1
  368. package/dist/components/Chat/Chat.cjs.map +1 -1
  369. package/dist/components/Chat/Chat.js.map +1 -1
  370. package/dist/components/Chat/Chat.module.cjs.map +1 -1
  371. package/dist/components/Chat/Chat.module.js.map +1 -1
  372. package/dist/components/Chat/ChatActionsMenu.cjs.map +1 -1
  373. package/dist/components/Chat/ChatActionsMenu.js.map +1 -1
  374. package/dist/components/Chat/ChatAttachments.cjs.map +1 -1
  375. package/dist/components/Chat/ChatAttachments.js.map +1 -1
  376. package/dist/components/Chat/ChatBubble.cjs.map +1 -1
  377. package/dist/components/Chat/ChatBubble.js.map +1 -1
  378. package/dist/components/Chat/ChatComposer.cjs.map +1 -1
  379. package/dist/components/Chat/ChatComposer.js.map +1 -1
  380. package/dist/components/Chat/chat-groups.cjs +1 -1
  381. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  382. package/dist/components/Chat/chat-groups.js +2 -6
  383. package/dist/components/Chat/chat-groups.js.map +1 -1
  384. package/dist/components/Chat/chat-receipt.cjs.map +1 -1
  385. package/dist/components/Chat/chat-receipt.js.map +1 -1
  386. package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
  387. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  388. package/dist/components/Checkbox/Checkbox.module.cjs.map +1 -1
  389. package/dist/components/Checkbox/Checkbox.module.js.map +1 -1
  390. package/dist/components/ChipInput/ChipInput.cjs +1 -1
  391. package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
  392. package/dist/components/ChipInput/ChipInput.js +2 -12
  393. package/dist/components/ChipInput/ChipInput.js.map +1 -1
  394. package/dist/components/ChipInput/ChipInput.module.cjs.map +1 -1
  395. package/dist/components/ChipInput/ChipInput.module.js.map +1 -1
  396. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  397. package/dist/components/ClickOutside/ClickOutside.js.map +1 -1
  398. package/dist/components/CodeBlock/CodeBlock.cjs +1 -1
  399. package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
  400. package/dist/components/CodeBlock/CodeBlock.js +1 -1
  401. package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
  402. package/dist/components/CodeBlock/CodeBlock.module.cjs.map +1 -1
  403. package/dist/components/CodeBlock/CodeBlock.module.js.map +1 -1
  404. package/dist/components/CodeBlock/tokenize.cjs +1 -1
  405. package/dist/components/CodeBlock/tokenize.cjs.map +1 -1
  406. package/dist/components/CodeBlock/tokenize.js +54 -25
  407. package/dist/components/CodeBlock/tokenize.js.map +1 -1
  408. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  409. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  410. package/dist/components/Collapsible/Collapsible.module.cjs.map +1 -1
  411. package/dist/components/Collapsible/Collapsible.module.js.map +1 -1
  412. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  413. package/dist/components/Combobox/Combobox.js.map +1 -1
  414. package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
  415. package/dist/components/Combobox/Combobox.module.js.map +1 -1
  416. package/dist/components/Combobox/use-listbox-dismiss.cjs.map +1 -1
  417. package/dist/components/Combobox/use-listbox-dismiss.js.map +1 -1
  418. package/dist/components/Command/Command.cjs +1 -1
  419. package/dist/components/Command/Command.cjs.map +1 -1
  420. package/dist/components/Command/Command.js +4 -11
  421. package/dist/components/Command/Command.js.map +1 -1
  422. package/dist/components/Command/Command.module.cjs.map +1 -1
  423. package/dist/components/Command/Command.module.js.map +1 -1
  424. package/dist/components/ConditionalWrapper/ConditionalWrapper.cjs.map +1 -1
  425. package/dist/components/ConditionalWrapper/ConditionalWrapper.js.map +1 -1
  426. package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  427. package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
  428. package/dist/components/ContextMenu/ContextMenu.cjs +1 -1
  429. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  430. package/dist/components/ContextMenu/ContextMenu.js +1 -1
  431. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  432. package/dist/components/ContextMenu/ContextMenu.module.cjs.map +1 -1
  433. package/dist/components/ContextMenu/ContextMenu.module.js.map +1 -1
  434. package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
  435. package/dist/components/CopyButton/CopyButton.js.map +1 -1
  436. package/dist/components/CopyButton/CopyButton.module.cjs.map +1 -1
  437. package/dist/components/CopyButton/CopyButton.module.js.map +1 -1
  438. package/dist/components/DataList/DataList.cjs.map +1 -1
  439. package/dist/components/DataList/DataList.js.map +1 -1
  440. package/dist/components/DataList/DataList.module.cjs.map +1 -1
  441. package/dist/components/DataList/DataList.module.js.map +1 -1
  442. package/dist/components/DataTable/DataTable.cjs +1 -1
  443. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  444. package/dist/components/DataTable/DataTable.js +6 -14
  445. package/dist/components/DataTable/DataTable.js.map +1 -1
  446. package/dist/components/DataTable/DataTable.module.cjs.map +1 -1
  447. package/dist/components/DataTable/DataTable.module.js.map +1 -1
  448. package/dist/components/DataTable/EditableCell.cjs +1 -1
  449. package/dist/components/DataTable/EditableCell.cjs.map +1 -1
  450. package/dist/components/DataTable/EditableCell.js +1 -9
  451. package/dist/components/DataTable/EditableCell.js.map +1 -1
  452. package/dist/components/DataTable/LoadingRows.cjs.map +1 -1
  453. package/dist/components/DataTable/LoadingRows.js.map +1 -1
  454. package/dist/components/DataTable/edit-labels.cjs.map +1 -1
  455. package/dist/components/DataTable/edit-labels.js.map +1 -1
  456. package/dist/components/DataTable/use-dev-warnings.cjs.map +1 -1
  457. package/dist/components/DataTable/use-dev-warnings.js.map +1 -1
  458. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  459. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  460. package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
  461. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  462. package/dist/components/DateRangePicker/DateRangePicker.module.cjs.map +1 -1
  463. package/dist/components/DateRangePicker/DateRangePicker.module.js.map +1 -1
  464. package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
  465. package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
  466. package/dist/components/DescriptionList/DescriptionList.module.cjs.map +1 -1
  467. package/dist/components/DescriptionList/DescriptionList.module.js.map +1 -1
  468. package/dist/components/Divider/Divider.cjs.map +1 -1
  469. package/dist/components/Divider/Divider.js.map +1 -1
  470. package/dist/components/Divider/Divider.module.cjs.map +1 -1
  471. package/dist/components/Divider/Divider.module.js.map +1 -1
  472. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  473. package/dist/components/Drawer/Drawer.js.map +1 -1
  474. package/dist/components/Drawer/Drawer.module.cjs.map +1 -1
  475. package/dist/components/Drawer/Drawer.module.js.map +1 -1
  476. package/dist/components/DropdownMenu/DropdownMenu.cjs +1 -1
  477. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  478. package/dist/components/DropdownMenu/DropdownMenu.js +2 -14
  479. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  480. package/dist/components/DropdownMenu/DropdownMenu.module.cjs.map +1 -1
  481. package/dist/components/DropdownMenu/DropdownMenu.module.js.map +1 -1
  482. package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
  483. package/dist/components/Dropzone/Dropzone.js.map +1 -1
  484. package/dist/components/Dropzone/Dropzone.module.cjs.map +1 -1
  485. package/dist/components/Dropzone/Dropzone.module.js.map +1 -1
  486. package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
  487. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  488. package/dist/components/EmptyState/EmptyState.module.cjs.map +1 -1
  489. package/dist/components/EmptyState/EmptyState.module.js.map +1 -1
  490. package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
  491. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  492. package/dist/components/ErrorState/ErrorState.module.cjs.map +1 -1
  493. package/dist/components/ErrorState/ErrorState.module.js.map +1 -1
  494. package/dist/components/ErrorText/ErrorText.cjs.map +1 -1
  495. package/dist/components/ErrorText/ErrorText.js.map +1 -1
  496. package/dist/components/ErrorText/ErrorText.module.cjs.map +1 -1
  497. package/dist/components/ErrorText/ErrorText.module.js.map +1 -1
  498. package/dist/components/FileUpload/FileUpload.cjs +1 -1
  499. package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
  500. package/dist/components/FileUpload/FileUpload.js +7 -17
  501. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  502. package/dist/components/FileUpload/FileUpload.module.cjs.map +1 -1
  503. package/dist/components/FileUpload/FileUpload.module.js.map +1 -1
  504. package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
  505. package/dist/components/FilterBar/FilterBar.js.map +1 -1
  506. package/dist/components/FilterBar/FilterBar.module.cjs.map +1 -1
  507. package/dist/components/FilterBar/FilterBar.module.js.map +1 -1
  508. package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
  509. package/dist/components/FilterBar/filter-apply.js.map +1 -1
  510. package/dist/components/FilterBar/filter-model.cjs.map +1 -1
  511. package/dist/components/FilterBar/filter-model.js.map +1 -1
  512. package/dist/components/FilterBar/filter-query.cjs +1 -1
  513. package/dist/components/FilterBar/filter-query.cjs.map +1 -1
  514. package/dist/components/FilterBar/filter-query.js +2 -5
  515. package/dist/components/FilterBar/filter-query.js.map +1 -1
  516. package/dist/components/FilterPanel/FilterPanel.cjs.map +1 -1
  517. package/dist/components/FilterPanel/FilterPanel.js.map +1 -1
  518. package/dist/components/FilterPanel/FilterPanel.module.cjs.map +1 -1
  519. package/dist/components/FilterPanel/FilterPanel.module.js.map +1 -1
  520. package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
  521. package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
  522. package/dist/components/FloatingActionButton/FloatingActionButton.module.cjs.map +1 -1
  523. package/dist/components/FloatingActionButton/FloatingActionButton.module.js.map +1 -1
  524. package/dist/components/For/For.cjs.map +1 -1
  525. package/dist/components/For/For.js.map +1 -1
  526. package/dist/components/Form/Form.cjs.map +1 -1
  527. package/dist/components/Form/Form.js.map +1 -1
  528. package/dist/components/Form/Form.module.cjs.map +1 -1
  529. package/dist/components/Form/Form.module.js.map +1 -1
  530. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  531. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  532. package/dist/components/HoverCard/HoverCard.module.cjs.map +1 -1
  533. package/dist/components/HoverCard/HoverCard.module.js.map +1 -1
  534. package/dist/components/Image/Image.cjs.map +1 -1
  535. package/dist/components/Image/Image.js.map +1 -1
  536. package/dist/components/Image/Image.module.cjs.map +1 -1
  537. package/dist/components/Image/Image.module.js.map +1 -1
  538. package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
  539. package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
  540. package/dist/components/ImageCropper/ImageCropper.js +4 -8
  541. package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
  542. package/dist/components/ImageCropper/ImageCropper.module.cjs.map +1 -1
  543. package/dist/components/ImageCropper/ImageCropper.module.js.map +1 -1
  544. package/dist/components/ImageCropper/crop-geometry.cjs.map +1 -1
  545. package/dist/components/ImageCropper/crop-geometry.js.map +1 -1
  546. package/dist/components/Input/Input.cjs.map +1 -1
  547. package/dist/components/Input/Input.js.map +1 -1
  548. package/dist/components/Input/Input.module.cjs.map +1 -1
  549. package/dist/components/Input/Input.module.js.map +1 -1
  550. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  551. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  552. package/dist/components/InstallBanner/InstallBanner.module.cjs.map +1 -1
  553. package/dist/components/InstallBanner/InstallBanner.module.js.map +1 -1
  554. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  555. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  556. package/dist/components/InstallButton/InstallButton.module.cjs.map +1 -1
  557. package/dist/components/InstallButton/InstallButton.module.js.map +1 -1
  558. package/dist/components/InstallButton/install-hints.cjs.map +1 -1
  559. package/dist/components/InstallButton/install-hints.js.map +1 -1
  560. package/dist/components/Kanban/Kanban.cjs.map +1 -1
  561. package/dist/components/Kanban/Kanban.js.map +1 -1
  562. package/dist/components/Kanban/Kanban.module.cjs.map +1 -1
  563. package/dist/components/Kanban/Kanban.module.js.map +1 -1
  564. package/dist/components/Kbd/Kbd.cjs.map +1 -1
  565. package/dist/components/Kbd/Kbd.js.map +1 -1
  566. package/dist/components/Kbd/Kbd.module.cjs.map +1 -1
  567. package/dist/components/Kbd/Kbd.module.js.map +1 -1
  568. package/dist/components/Label/Label.cjs.map +1 -1
  569. package/dist/components/Label/Label.js.map +1 -1
  570. package/dist/components/Label/Label.module.cjs.map +1 -1
  571. package/dist/components/Label/Label.module.js.map +1 -1
  572. package/dist/components/Layout/Layout.cjs.map +1 -1
  573. package/dist/components/Layout/Layout.js.map +1 -1
  574. package/dist/components/Layout/Layout.module.cjs.map +1 -1
  575. package/dist/components/Layout/Layout.module.js.map +1 -1
  576. package/dist/components/Lightbox/Lightbox.cjs +1 -1
  577. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  578. package/dist/components/Lightbox/Lightbox.js +1 -1
  579. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  580. package/dist/components/Lightbox/Lightbox.module.cjs.map +1 -1
  581. package/dist/components/Lightbox/Lightbox.module.js.map +1 -1
  582. package/dist/components/ListTile/ListTile.cjs.map +1 -1
  583. package/dist/components/ListTile/ListTile.js.map +1 -1
  584. package/dist/components/ListTile/ListTile.module.cjs.map +1 -1
  585. package/dist/components/ListTile/ListTile.module.js.map +1 -1
  586. package/dist/components/Markdown/Markdown.cjs.map +1 -1
  587. package/dist/components/Markdown/Markdown.js.map +1 -1
  588. package/dist/components/Markdown/Markdown.module.cjs.map +1 -1
  589. package/dist/components/Markdown/Markdown.module.js.map +1 -1
  590. package/dist/components/Markdown/markdown-parse.cjs +6 -6
  591. package/dist/components/Markdown/markdown-parse.cjs.map +1 -1
  592. package/dist/components/Markdown/markdown-parse.js +94 -96
  593. package/dist/components/Markdown/markdown-parse.js.map +1 -1
  594. package/dist/components/Masonry/Masonry.cjs.map +1 -1
  595. package/dist/components/Masonry/Masonry.js.map +1 -1
  596. package/dist/components/Masonry/Masonry.module.cjs.map +1 -1
  597. package/dist/components/Masonry/Masonry.module.js.map +1 -1
  598. package/dist/components/Masonry/masonry-layout.cjs.map +1 -1
  599. package/dist/components/Masonry/masonry-layout.js.map +1 -1
  600. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  601. package/dist/components/Menubar/Menubar.js.map +1 -1
  602. package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
  603. package/dist/components/Menubar/Menubar.module.js.map +1 -1
  604. package/dist/components/Modal/Modal.cjs.map +1 -1
  605. package/dist/components/Modal/Modal.js.map +1 -1
  606. package/dist/components/Modal/Modal.module.cjs.map +1 -1
  607. package/dist/components/Modal/Modal.module.js.map +1 -1
  608. package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
  609. package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
  610. package/dist/components/ModalsManager/ModalsManager.module.cjs.map +1 -1
  611. package/dist/components/ModalsManager/ModalsManager.module.js.map +1 -1
  612. package/dist/components/Money/Money.cjs.map +1 -1
  613. package/dist/components/Money/Money.js.map +1 -1
  614. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  615. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  616. package/dist/components/MultiSelect/MultiSelect.module.cjs.map +1 -1
  617. package/dist/components/MultiSelect/MultiSelect.module.js.map +1 -1
  618. package/dist/components/NProgress/NProgress.cjs.map +1 -1
  619. package/dist/components/NProgress/NProgress.js.map +1 -1
  620. package/dist/components/NProgress/NProgress.module.cjs.map +1 -1
  621. package/dist/components/NProgress/NProgress.module.js.map +1 -1
  622. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  623. package/dist/components/Navbar/Navbar.js.map +1 -1
  624. package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
  625. package/dist/components/Navbar/Navbar.module.js.map +1 -1
  626. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  627. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  628. package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
  629. package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
  630. package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
  631. package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
  632. package/dist/components/NavigationRail/NavigationRail.module.cjs.map +1 -1
  633. package/dist/components/NavigationRail/NavigationRail.module.js.map +1 -1
  634. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
  635. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
  636. package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -1
  637. package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -1
  638. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
  639. package/dist/components/NotificationCenter/use-notification-inbox.js.map +1 -1
  640. package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
  641. package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
  642. package/dist/components/OfflineIndicator/OfflineIndicator.module.cjs.map +1 -1
  643. package/dist/components/OfflineIndicator/OfflineIndicator.module.js.map +1 -1
  644. package/dist/components/Page/Page.cjs.map +1 -1
  645. package/dist/components/Page/Page.js.map +1 -1
  646. package/dist/components/Page/Page.module.cjs.map +1 -1
  647. package/dist/components/Page/Page.module.js.map +1 -1
  648. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  649. package/dist/components/Pagination/Pagination.js.map +1 -1
  650. package/dist/components/Pagination/Pagination.module.cjs.map +1 -1
  651. package/dist/components/Pagination/Pagination.module.js.map +1 -1
  652. package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
  653. package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
  654. package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
  655. package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
  656. package/dist/components/PinInput/PinInput.cjs.map +1 -1
  657. package/dist/components/PinInput/PinInput.js.map +1 -1
  658. package/dist/components/PinInput/PinInput.module.cjs.map +1 -1
  659. package/dist/components/PinInput/PinInput.module.js.map +1 -1
  660. package/dist/components/Popover/Popover.cjs.map +1 -1
  661. package/dist/components/Popover/Popover.js.map +1 -1
  662. package/dist/components/Popover/Popover.module.cjs.map +1 -1
  663. package/dist/components/Popover/Popover.module.js.map +1 -1
  664. package/dist/components/Portal/Portal.cjs.map +1 -1
  665. package/dist/components/Portal/Portal.js.map +1 -1
  666. package/dist/components/Portal/anchor-position.cjs.map +1 -1
  667. package/dist/components/Portal/anchor-position.js.map +1 -1
  668. package/dist/components/Portal/escape-layer.cjs.map +1 -1
  669. package/dist/components/Portal/escape-layer.js.map +1 -1
  670. package/dist/components/Portal/portal-host.cjs.map +1 -1
  671. package/dist/components/Portal/portal-host.js.map +1 -1
  672. package/dist/components/Portal/tab-bridge.cjs +1 -1
  673. package/dist/components/Portal/tab-bridge.cjs.map +1 -1
  674. package/dist/components/Portal/tab-bridge.js +1 -5
  675. package/dist/components/Portal/tab-bridge.js.map +1 -1
  676. package/dist/components/Progress/Progress.cjs.map +1 -1
  677. package/dist/components/Progress/Progress.js.map +1 -1
  678. package/dist/components/Progress/Progress.module.cjs.map +1 -1
  679. package/dist/components/Progress/Progress.module.js.map +1 -1
  680. package/dist/components/QRCode/QRCode.cjs.map +1 -1
  681. package/dist/components/QRCode/QRCode.js.map +1 -1
  682. package/dist/components/QRCode/QRCode.module.cjs.map +1 -1
  683. package/dist/components/QRCode/QRCode.module.js.map +1 -1
  684. package/dist/components/QRCode/qr-encode.cjs +1 -1
  685. package/dist/components/QRCode/qr-encode.cjs.map +1 -1
  686. package/dist/components/QRCode/qr-encode.js +7 -13
  687. package/dist/components/QRCode/qr-encode.js.map +1 -1
  688. package/dist/components/QRCode/qr-tables.cjs.map +1 -1
  689. package/dist/components/QRCode/qr-tables.js.map +1 -1
  690. package/dist/components/Radio/Radio.cjs.map +1 -1
  691. package/dist/components/Radio/Radio.js.map +1 -1
  692. package/dist/components/Radio/Radio.module.cjs.map +1 -1
  693. package/dist/components/Radio/Radio.module.js.map +1 -1
  694. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  695. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  696. package/dist/components/RangeSlider/RangeSlider.module.cjs.map +1 -1
  697. package/dist/components/RangeSlider/RangeSlider.module.js.map +1 -1
  698. package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
  699. package/dist/components/RatingStars/RatingStars.js.map +1 -1
  700. package/dist/components/RatingStars/RatingStars.module.cjs.map +1 -1
  701. package/dist/components/RatingStars/RatingStars.module.js.map +1 -1
  702. package/dist/components/RefreshIndicator/RefreshIndicator.cjs +1 -1
  703. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  704. package/dist/components/RefreshIndicator/RefreshIndicator.js +10 -18
  705. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  706. package/dist/components/RefreshIndicator/RefreshIndicator.module.cjs.map +1 -1
  707. package/dist/components/RefreshIndicator/RefreshIndicator.module.js.map +1 -1
  708. package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
  709. package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
  710. package/dist/components/Resizable/Resizable.cjs +1 -1
  711. package/dist/components/Resizable/Resizable.cjs.map +1 -1
  712. package/dist/components/Resizable/Resizable.js +1 -9
  713. package/dist/components/Resizable/Resizable.js.map +1 -1
  714. package/dist/components/Resizable/Resizable.module.cjs.map +1 -1
  715. package/dist/components/Resizable/Resizable.module.js.map +1 -1
  716. package/dist/components/Responsive/Responsive.cjs.map +1 -1
  717. package/dist/components/Responsive/Responsive.js.map +1 -1
  718. package/dist/components/Reveal/Reveal.cjs.map +1 -1
  719. package/dist/components/Reveal/Reveal.js.map +1 -1
  720. package/dist/components/Reveal/Reveal.module.cjs.map +1 -1
  721. package/dist/components/Reveal/Reveal.module.js.map +1 -1
  722. package/dist/components/Reveal/reveal-threshold.cjs.map +1 -1
  723. package/dist/components/Reveal/reveal-threshold.js.map +1 -1
  724. package/dist/components/SafeArea/SafeArea.cjs.map +1 -1
  725. package/dist/components/SafeArea/SafeArea.js.map +1 -1
  726. package/dist/components/SafeArea/SafeArea.module.cjs.map +1 -1
  727. package/dist/components/SafeArea/SafeArea.module.js.map +1 -1
  728. package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
  729. package/dist/components/Scheduler/Scheduler.js.map +1 -1
  730. package/dist/components/Scheduler/Scheduler.module.cjs.map +1 -1
  731. package/dist/components/Scheduler/Scheduler.module.js.map +1 -1
  732. package/dist/components/Scheduler/scheduler-layout.cjs.map +1 -1
  733. package/dist/components/Scheduler/scheduler-layout.js.map +1 -1
  734. package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
  735. package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
  736. package/dist/components/ScrollArea/ScrollArea.module.cjs.map +1 -1
  737. package/dist/components/ScrollArea/ScrollArea.module.js.map +1 -1
  738. package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
  739. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  740. package/dist/components/SearchBar/SearchBar.module.cjs.map +1 -1
  741. package/dist/components/SearchBar/SearchBar.module.js.map +1 -1
  742. package/dist/components/SectionHeader/SectionHeader.cjs.map +1 -1
  743. package/dist/components/SectionHeader/SectionHeader.js.map +1 -1
  744. package/dist/components/SectionHeader/SectionHeader.module.cjs.map +1 -1
  745. package/dist/components/SectionHeader/SectionHeader.module.js.map +1 -1
  746. package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
  747. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  748. package/dist/components/SegmentedControl/SegmentedControl.module.cjs.map +1 -1
  749. package/dist/components/SegmentedControl/SegmentedControl.module.js.map +1 -1
  750. package/dist/components/Select/CaretIcon.cjs.map +1 -1
  751. package/dist/components/Select/CaretIcon.js.map +1 -1
  752. package/dist/components/Select/Select.cjs.map +1 -1
  753. package/dist/components/Select/Select.js.map +1 -1
  754. package/dist/components/Select/Select.module.cjs.map +1 -1
  755. package/dist/components/Select/Select.module.js.map +1 -1
  756. package/dist/components/Select/options.cjs.map +1 -1
  757. package/dist/components/Select/options.js.map +1 -1
  758. package/dist/components/Sidebar/Sidebar.cjs +1 -1
  759. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  760. package/dist/components/Sidebar/Sidebar.js +13 -23
  761. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  762. package/dist/components/Sidebar/Sidebar.module.cjs.map +1 -1
  763. package/dist/components/Sidebar/Sidebar.module.js.map +1 -1
  764. package/dist/components/Sidebar/SidebarEntry.cjs.map +1 -1
  765. package/dist/components/Sidebar/SidebarEntry.js.map +1 -1
  766. package/dist/components/Sidebar/active-nav-key.cjs.map +1 -1
  767. package/dist/components/Sidebar/active-nav-key.js.map +1 -1
  768. package/dist/components/SignaturePad/SignaturePad.cjs +1 -1
  769. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
  770. package/dist/components/SignaturePad/SignaturePad.js +1 -5
  771. package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
  772. package/dist/components/SignaturePad/SignaturePad.module.cjs.map +1 -1
  773. package/dist/components/SignaturePad/SignaturePad.module.js.map +1 -1
  774. package/dist/components/Skeleton/Skeleton.cjs.map +1 -1
  775. package/dist/components/Skeleton/Skeleton.js.map +1 -1
  776. package/dist/components/Skeleton/Skeleton.module.cjs.map +1 -1
  777. package/dist/components/Skeleton/Skeleton.module.js.map +1 -1
  778. package/dist/components/Slider/Slider.cjs.map +1 -1
  779. package/dist/components/Slider/Slider.js.map +1 -1
  780. package/dist/components/Slider/Slider.module.cjs.map +1 -1
  781. package/dist/components/Slider/Slider.module.js.map +1 -1
  782. package/dist/components/Spacer/Spacer.cjs.map +1 -1
  783. package/dist/components/Spacer/Spacer.js.map +1 -1
  784. package/dist/components/Spacer/Spacer.module.cjs.map +1 -1
  785. package/dist/components/Spacer/Spacer.module.js.map +1 -1
  786. package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
  787. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  788. package/dist/components/Sparkline/Sparkline.module.cjs.map +1 -1
  789. package/dist/components/Sparkline/Sparkline.module.js.map +1 -1
  790. package/dist/components/Sparkline/sparkline-geometry.cjs.map +1 -1
  791. package/dist/components/Sparkline/sparkline-geometry.js.map +1 -1
  792. package/dist/components/Spinner/Spinner.cjs.map +1 -1
  793. package/dist/components/Spinner/Spinner.js.map +1 -1
  794. package/dist/components/Spinner/Spinner.module.cjs.map +1 -1
  795. package/dist/components/Spinner/Spinner.module.js.map +1 -1
  796. package/dist/components/Stat/Stat.cjs.map +1 -1
  797. package/dist/components/Stat/Stat.js.map +1 -1
  798. package/dist/components/Stat/Stat.module.cjs.map +1 -1
  799. package/dist/components/Stat/Stat.module.js.map +1 -1
  800. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  801. package/dist/components/Stepper/Stepper.js.map +1 -1
  802. package/dist/components/Stepper/Stepper.module.cjs.map +1 -1
  803. package/dist/components/Stepper/Stepper.module.js.map +1 -1
  804. package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
  805. package/dist/components/StepperInput/StepperInput.js.map +1 -1
  806. package/dist/components/StepperInput/StepperInput.module.cjs.map +1 -1
  807. package/dist/components/StepperInput/StepperInput.module.js.map +1 -1
  808. package/dist/components/Switch/Switch.cjs.map +1 -1
  809. package/dist/components/Switch/Switch.js.map +1 -1
  810. package/dist/components/Switch/Switch.module.cjs.map +1 -1
  811. package/dist/components/Switch/Switch.module.js.map +1 -1
  812. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  813. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  814. package/dist/components/SyncStatusBadge/SyncStatusBadge.module.cjs.map +1 -1
  815. package/dist/components/SyncStatusBadge/SyncStatusBadge.module.js.map +1 -1
  816. package/dist/components/Table/Table.cjs.map +1 -1
  817. package/dist/components/Table/Table.js.map +1 -1
  818. package/dist/components/Table/Table.module.cjs.map +1 -1
  819. package/dist/components/Table/Table.module.js.map +1 -1
  820. package/dist/components/Tabs/Tabs.cjs.map +1 -1
  821. package/dist/components/Tabs/Tabs.js.map +1 -1
  822. package/dist/components/Tabs/Tabs.module.cjs.map +1 -1
  823. package/dist/components/Tabs/Tabs.module.js.map +1 -1
  824. package/dist/components/Tag/Tag.cjs.map +1 -1
  825. package/dist/components/Tag/Tag.js.map +1 -1
  826. package/dist/components/Tag/Tag.module.cjs.map +1 -1
  827. package/dist/components/Tag/Tag.module.js.map +1 -1
  828. package/dist/components/Textarea/Textarea.cjs.map +1 -1
  829. package/dist/components/Textarea/Textarea.js.map +1 -1
  830. package/dist/components/Textarea/Textarea.module.cjs.map +1 -1
  831. package/dist/components/Textarea/Textarea.module.js.map +1 -1
  832. package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
  833. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  834. package/dist/components/TimePicker/TimePicker.module.cjs.map +1 -1
  835. package/dist/components/TimePicker/TimePicker.module.js.map +1 -1
  836. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  837. package/dist/components/Timeline/Timeline.js.map +1 -1
  838. package/dist/components/Timeline/Timeline.module.cjs.map +1 -1
  839. package/dist/components/Timeline/Timeline.module.js.map +1 -1
  840. package/dist/components/Toast/Toast.module.cjs.map +1 -1
  841. package/dist/components/Toast/Toast.module.js.map +1 -1
  842. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  843. package/dist/components/Toast/ToastProvider.js.map +1 -1
  844. package/dist/components/Toggle/Toggle.cjs.map +1 -1
  845. package/dist/components/Toggle/Toggle.js.map +1 -1
  846. package/dist/components/Toggle/Toggle.module.cjs.map +1 -1
  847. package/dist/components/Toggle/Toggle.module.js.map +1 -1
  848. package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
  849. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  850. package/dist/components/ToggleGroup/ToggleGroup.module.cjs.map +1 -1
  851. package/dist/components/ToggleGroup/ToggleGroup.module.js.map +1 -1
  852. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  853. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  854. package/dist/components/Tooltip/Tooltip.module.cjs.map +1 -1
  855. package/dist/components/Tooltip/Tooltip.module.js.map +1 -1
  856. package/dist/components/Tour/Tour.cjs +1 -1
  857. package/dist/components/Tour/Tour.cjs.map +1 -1
  858. package/dist/components/Tour/Tour.js +1 -5
  859. package/dist/components/Tour/Tour.js.map +1 -1
  860. package/dist/components/Tour/Tour.module.cjs.map +1 -1
  861. package/dist/components/Tour/Tour.module.js.map +1 -1
  862. package/dist/components/Tour/tour-position.cjs.map +1 -1
  863. package/dist/components/Tour/tour-position.js.map +1 -1
  864. package/dist/components/Transfer/Transfer.cjs.map +1 -1
  865. package/dist/components/Transfer/Transfer.js.map +1 -1
  866. package/dist/components/Transfer/Transfer.module.cjs.map +1 -1
  867. package/dist/components/Transfer/Transfer.module.js.map +1 -1
  868. package/dist/components/Transfer/transfer-state.cjs.map +1 -1
  869. package/dist/components/Transfer/transfer-state.js.map +1 -1
  870. package/dist/components/TreeView/TreeView.cjs.map +1 -1
  871. package/dist/components/TreeView/TreeView.js.map +1 -1
  872. package/dist/components/TreeView/TreeView.module.cjs.map +1 -1
  873. package/dist/components/TreeView/TreeView.module.js.map +1 -1
  874. package/dist/components/TruncateText/TruncateText.cjs.map +1 -1
  875. package/dist/components/TruncateText/TruncateText.js.map +1 -1
  876. package/dist/components/TruncateText/TruncateText.module.cjs.map +1 -1
  877. package/dist/components/TruncateText/TruncateText.module.js.map +1 -1
  878. package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
  879. package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
  880. package/dist/components/UpdatePrompt/UpdatePrompt.module.cjs.map +1 -1
  881. package/dist/components/UpdatePrompt/UpdatePrompt.module.js.map +1 -1
  882. package/dist/components/VideoPlayer/VideoPlayer.cjs +1 -1
  883. package/dist/components/VideoPlayer/VideoPlayer.cjs.map +1 -1
  884. package/dist/components/VideoPlayer/VideoPlayer.js +1 -7
  885. package/dist/components/VideoPlayer/VideoPlayer.js.map +1 -1
  886. package/dist/components/VideoPlayer/VideoPlayer.module.cjs.map +1 -1
  887. package/dist/components/VideoPlayer/VideoPlayer.module.js.map +1 -1
  888. package/dist/components/VideoPlayer/playback-rates.cjs.map +1 -1
  889. package/dist/components/VideoPlayer/playback-rates.js.map +1 -1
  890. package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
  891. package/dist/components/VirtualList/VirtualList.js.map +1 -1
  892. package/dist/components/VirtualList/VirtualList.module.cjs.map +1 -1
  893. package/dist/components/VirtualList/VirtualList.module.js.map +1 -1
  894. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
  895. package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
  896. package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -1
  897. package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -1
  898. package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
  899. package/dist/components/VisuallyHidden/VisuallyHidden.js.map +1 -1
  900. package/dist/components/VisuallyHidden/VisuallyHidden.module.cjs.map +1 -1
  901. package/dist/components/VisuallyHidden/VisuallyHidden.module.js.map +1 -1
  902. package/dist/components/Wizard/Wizard.cjs +1 -1
  903. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  904. package/dist/components/Wizard/Wizard.js +4 -11
  905. package/dist/components/Wizard/Wizard.js.map +1 -1
  906. package/dist/components/Wizard/Wizard.module.cjs.map +1 -1
  907. package/dist/components/Wizard/Wizard.module.js.map +1 -1
  908. package/dist/data/create-data-provider.cjs.map +1 -1
  909. package/dist/data/create-data-provider.js.map +1 -1
  910. package/dist/data/data-provider-context.cjs.map +1 -1
  911. package/dist/data/data-provider-context.js.map +1 -1
  912. package/dist/data/use-resource.cjs.map +1 -1
  913. package/dist/data/use-resource.js.map +1 -1
  914. package/dist/editor/RichTextEditor.cjs.map +1 -1
  915. package/dist/editor/RichTextEditor.js.map +1 -1
  916. package/dist/editor/RichTextEditor.module.cjs.map +1 -1
  917. package/dist/editor/RichTextEditor.module.js.map +1 -1
  918. package/dist/editor.js +1 -2
  919. package/dist/error-boundary/ErrorBoundary.cjs.map +1 -1
  920. package/dist/error-boundary/ErrorBoundary.js.map +1 -1
  921. package/dist/error-boundary/use-error-handler.cjs.map +1 -1
  922. package/dist/error-boundary/use-error-handler.js.map +1 -1
  923. package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
  924. package/dist/feature-flags/FeatureFlagsProvider.js.map +1 -1
  925. package/dist/feature-flags/growthbook-adapter.cjs.map +1 -1
  926. package/dist/feature-flags/growthbook-adapter.js.map +1 -1
  927. package/dist/feature-flags/in-memory-adapter.cjs.map +1 -1
  928. package/dist/feature-flags/in-memory-adapter.js.map +1 -1
  929. package/dist/feature-flags/launchdarkly-adapter.cjs.map +1 -1
  930. package/dist/feature-flags/launchdarkly-adapter.js.map +1 -1
  931. package/dist/forms/FormField.cjs.map +1 -1
  932. package/dist/forms/FormField.js.map +1 -1
  933. package/dist/forms/br-validators.cjs.map +1 -1
  934. package/dist/forms/br-validators.js.map +1 -1
  935. package/dist/forms/masked-inputs.cjs.map +1 -1
  936. package/dist/forms/masked-inputs.js.map +1 -1
  937. package/dist/forms/use-viacep.cjs.map +1 -1
  938. package/dist/forms/use-viacep.js.map +1 -1
  939. package/dist/forms/use-zod-form.cjs.map +1 -1
  940. package/dist/forms/use-zod-form.js.map +1 -1
  941. package/dist/forms/validate-form.cjs.map +1 -1
  942. package/dist/forms/validate-form.js.map +1 -1
  943. package/dist/forms/zod-resolver.cjs.map +1 -1
  944. package/dist/forms/zod-resolver.js.map +1 -1
  945. package/dist/geo/TrajectoryMap.cjs.map +1 -1
  946. package/dist/geo/TrajectoryMap.js.map +1 -1
  947. package/dist/geo/TrajectoryMap.module.cjs.map +1 -1
  948. package/dist/geo/TrajectoryMap.module.js.map +1 -1
  949. package/dist/geo/bounds.cjs.map +1 -1
  950. package/dist/geo/bounds.js.map +1 -1
  951. package/dist/geo/create-position-tracker.cjs +1 -1
  952. package/dist/geo/create-position-tracker.cjs.map +1 -1
  953. package/dist/geo/create-position-tracker.js +1 -7
  954. package/dist/geo/create-position-tracker.js.map +1 -1
  955. package/dist/geo/distance.cjs.map +1 -1
  956. package/dist/geo/distance.js.map +1 -1
  957. package/dist/geo/estimate.cjs.map +1 -1
  958. package/dist/geo/estimate.js.map +1 -1
  959. package/dist/geo/leaflet-map.cjs.map +1 -1
  960. package/dist/geo/leaflet-map.js.map +1 -1
  961. package/dist/geo/projection.cjs.map +1 -1
  962. package/dist/geo/projection.js.map +1 -1
  963. package/dist/geo/routing.cjs.map +1 -1
  964. package/dist/geo/routing.js.map +1 -1
  965. package/dist/geo/types.cjs.map +1 -1
  966. package/dist/geo/types.js.map +1 -1
  967. package/dist/geo/use-position-tracker.cjs.map +1 -1
  968. package/dist/geo/use-position-tracker.js.map +1 -1
  969. package/dist/hooks/pwa-env.cjs.map +1 -1
  970. package/dist/hooks/pwa-env.js.map +1 -1
  971. package/dist/hooks/tab-sequence.cjs.map +1 -1
  972. package/dist/hooks/tab-sequence.js.map +1 -1
  973. package/dist/hooks/use-announce.cjs +1 -1
  974. package/dist/hooks/use-announce.cjs.map +1 -1
  975. package/dist/hooks/use-announce.js +2 -2
  976. package/dist/hooks/use-announce.js.map +1 -1
  977. package/dist/hooks/use-async.cjs.map +1 -1
  978. package/dist/hooks/use-async.js.map +1 -1
  979. package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
  980. package/dist/hooks/use-before-install-prompt.js.map +1 -1
  981. package/dist/hooks/use-breakpoint.cjs.map +1 -1
  982. package/dist/hooks/use-breakpoint.js.map +1 -1
  983. package/dist/hooks/use-click-outside.cjs.map +1 -1
  984. package/dist/hooks/use-click-outside.js.map +1 -1
  985. package/dist/hooks/use-client-filter.cjs.map +1 -1
  986. package/dist/hooks/use-client-filter.js.map +1 -1
  987. package/dist/hooks/use-clipboard.cjs.map +1 -1
  988. package/dist/hooks/use-clipboard.js.map +1 -1
  989. package/dist/hooks/use-countdown.cjs.map +1 -1
  990. package/dist/hooks/use-countdown.js.map +1 -1
  991. package/dist/hooks/use-counter.cjs.map +1 -1
  992. package/dist/hooks/use-counter.js.map +1 -1
  993. package/dist/hooks/use-debounce.cjs.map +1 -1
  994. package/dist/hooks/use-debounce.js.map +1 -1
  995. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  996. package/dist/hooks/use-deep-memo.js.map +1 -1
  997. package/dist/hooks/use-disclosure.cjs.map +1 -1
  998. package/dist/hooks/use-disclosure.js.map +1 -1
  999. package/dist/hooks/use-document-title.cjs.map +1 -1
  1000. package/dist/hooks/use-document-title.js.map +1 -1
  1001. package/dist/hooks/use-document-visibility.cjs.map +1 -1
  1002. package/dist/hooks/use-document-visibility.js.map +1 -1
  1003. package/dist/hooks/use-draft-filters.cjs.map +1 -1
  1004. package/dist/hooks/use-draft-filters.js.map +1 -1
  1005. package/dist/hooks/use-event-listener.cjs.map +1 -1
  1006. package/dist/hooks/use-event-listener.js.map +1 -1
  1007. package/dist/hooks/use-favicon.cjs.map +1 -1
  1008. package/dist/hooks/use-favicon.js.map +1 -1
  1009. package/dist/hooks/use-focus-trap.cjs.map +1 -1
  1010. package/dist/hooks/use-focus-trap.js.map +1 -1
  1011. package/dist/hooks/use-fullscreen-element.cjs.map +1 -1
  1012. package/dist/hooks/use-fullscreen-element.js.map +1 -1
  1013. package/dist/hooks/use-fullscreen.cjs +1 -1
  1014. package/dist/hooks/use-fullscreen.cjs.map +1 -1
  1015. package/dist/hooks/use-fullscreen.js +7 -23
  1016. package/dist/hooks/use-fullscreen.js.map +1 -1
  1017. package/dist/hooks/use-geolocation.cjs.map +1 -1
  1018. package/dist/hooks/use-geolocation.js.map +1 -1
  1019. package/dist/hooks/use-hover.cjs.map +1 -1
  1020. package/dist/hooks/use-hover.js.map +1 -1
  1021. package/dist/hooks/use-idle.cjs.map +1 -1
  1022. package/dist/hooks/use-idle.js.map +1 -1
  1023. package/dist/hooks/use-install-prompt.cjs +1 -1
  1024. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  1025. package/dist/hooks/use-install-prompt.js +1 -1
  1026. package/dist/hooks/use-install-prompt.js.map +1 -1
  1027. package/dist/hooks/use-intersection-observer.cjs.map +1 -1
  1028. package/dist/hooks/use-intersection-observer.js.map +1 -1
  1029. package/dist/hooks/use-interval.cjs.map +1 -1
  1030. package/dist/hooks/use-interval.js.map +1 -1
  1031. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  1032. package/dist/hooks/use-is-first-render.js.map +1 -1
  1033. package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
  1034. package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
  1035. package/dist/hooks/use-latest-ref.cjs.map +1 -1
  1036. package/dist/hooks/use-latest-ref.js.map +1 -1
  1037. package/dist/hooks/use-list-state.cjs.map +1 -1
  1038. package/dist/hooks/use-list-state.js.map +1 -1
  1039. package/dist/hooks/use-local-storage.cjs +1 -1
  1040. package/dist/hooks/use-local-storage.cjs.map +1 -1
  1041. package/dist/hooks/use-local-storage.js +2 -5
  1042. package/dist/hooks/use-local-storage.js.map +1 -1
  1043. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  1044. package/dist/hooks/use-long-press-handlers.js.map +1 -1
  1045. package/dist/hooks/use-long-press.cjs.map +1 -1
  1046. package/dist/hooks/use-long-press.js.map +1 -1
  1047. package/dist/hooks/use-map.cjs.map +1 -1
  1048. package/dist/hooks/use-map.js.map +1 -1
  1049. package/dist/hooks/use-media-devices.cjs.map +1 -1
  1050. package/dist/hooks/use-media-devices.js.map +1 -1
  1051. package/dist/hooks/use-media-permission.cjs +1 -1
  1052. package/dist/hooks/use-media-permission.cjs.map +1 -1
  1053. package/dist/hooks/use-media-permission.js +2 -5
  1054. package/dist/hooks/use-media-permission.js.map +1 -1
  1055. package/dist/hooks/use-media-query.cjs.map +1 -1
  1056. package/dist/hooks/use-media-query.js.map +1 -1
  1057. package/dist/hooks/use-object-url.cjs.map +1 -1
  1058. package/dist/hooks/use-object-url.js.map +1 -1
  1059. package/dist/hooks/use-online.cjs.map +1 -1
  1060. package/dist/hooks/use-online.js.map +1 -1
  1061. package/dist/hooks/use-pagination.cjs.map +1 -1
  1062. package/dist/hooks/use-pagination.js.map +1 -1
  1063. package/dist/hooks/use-previous.cjs.map +1 -1
  1064. package/dist/hooks/use-previous.js.map +1 -1
  1065. package/dist/hooks/use-push-to-talk.cjs.map +1 -1
  1066. package/dist/hooks/use-push-to-talk.js.map +1 -1
  1067. package/dist/hooks/use-queue.cjs.map +1 -1
  1068. package/dist/hooks/use-queue.js.map +1 -1
  1069. package/dist/hooks/use-resize-observer.cjs.map +1 -1
  1070. package/dist/hooks/use-resize-observer.js.map +1 -1
  1071. package/dist/hooks/use-scroll-lock.cjs.map +1 -1
  1072. package/dist/hooks/use-scroll-lock.js.map +1 -1
  1073. package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
  1074. package/dist/hooks/use-scroll-overflow.js.map +1 -1
  1075. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  1076. package/dist/hooks/use-service-worker-update.js.map +1 -1
  1077. package/dist/hooks/use-set.cjs.map +1 -1
  1078. package/dist/hooks/use-set.js.map +1 -1
  1079. package/dist/hooks/use-sortable.cjs.map +1 -1
  1080. package/dist/hooks/use-sortable.js.map +1 -1
  1081. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  1082. package/dist/hooks/use-stable-callback.js.map +1 -1
  1083. package/dist/hooks/use-storage-estimate.cjs.map +1 -1
  1084. package/dist/hooks/use-storage-estimate.js.map +1 -1
  1085. package/dist/hooks/use-throttle.cjs.map +1 -1
  1086. package/dist/hooks/use-throttle.js.map +1 -1
  1087. package/dist/hooks/use-timeout.cjs.map +1 -1
  1088. package/dist/hooks/use-timeout.js.map +1 -1
  1089. package/dist/hooks/use-toggle.cjs.map +1 -1
  1090. package/dist/hooks/use-toggle.js.map +1 -1
  1091. package/dist/hooks/use-typewriter.cjs.map +1 -1
  1092. package/dist/hooks/use-typewriter.js.map +1 -1
  1093. package/dist/hooks/use-window-size.cjs.map +1 -1
  1094. package/dist/hooks/use-window-size.js.map +1 -1
  1095. package/dist/http/api-client.cjs.map +1 -1
  1096. package/dist/http/api-client.js.map +1 -1
  1097. package/dist/http/build-url.cjs.map +1 -1
  1098. package/dist/http/build-url.js.map +1 -1
  1099. package/dist/http/credential-scope.cjs.map +1 -1
  1100. package/dist/http/credential-scope.js.map +1 -1
  1101. package/dist/http/csrf.cjs.map +1 -1
  1102. package/dist/http/csrf.js.map +1 -1
  1103. package/dist/http/decode-response.cjs.map +1 -1
  1104. package/dist/http/decode-response.js.map +1 -1
  1105. package/dist/http/describe-api-error.cjs.map +1 -1
  1106. package/dist/http/describe-api-error.js.map +1 -1
  1107. package/dist/http/errors.cjs.map +1 -1
  1108. package/dist/http/errors.js.map +1 -1
  1109. package/dist/http/idempotency.cjs.map +1 -1
  1110. package/dist/http/idempotency.js.map +1 -1
  1111. package/dist/http/parse-response.cjs.map +1 -1
  1112. package/dist/http/parse-response.js.map +1 -1
  1113. package/dist/http/resumable-upload.cjs +1 -1
  1114. package/dist/http/resumable-upload.cjs.map +1 -1
  1115. package/dist/http/resumable-upload.js +141 -105
  1116. package/dist/http/resumable-upload.js.map +1 -1
  1117. package/dist/http/retry.cjs +1 -1
  1118. package/dist/http/retry.cjs.map +1 -1
  1119. package/dist/http/retry.js +5 -6
  1120. package/dist/http/retry.js.map +1 -1
  1121. package/dist/http/timeout.cjs.map +1 -1
  1122. package/dist/http/timeout.js.map +1 -1
  1123. package/dist/http/upload-with-progress.cjs +1 -1
  1124. package/dist/http/upload-with-progress.cjs.map +1 -1
  1125. package/dist/http/upload-with-progress.js +2 -7
  1126. package/dist/http/upload-with-progress.js.map +1 -1
  1127. package/dist/http/use-describe-api-error.cjs.map +1 -1
  1128. package/dist/http/use-describe-api-error.js.map +1 -1
  1129. package/dist/http/use-poll.cjs +1 -1
  1130. package/dist/http/use-poll.cjs.map +1 -1
  1131. package/dist/http/use-poll.js +2 -5
  1132. package/dist/http/use-poll.js.map +1 -1
  1133. package/dist/i18n/I18nProvider.cjs.map +1 -1
  1134. package/dist/i18n/I18nProvider.js.map +1 -1
  1135. package/dist/i18n/create-i18n.cjs.map +1 -1
  1136. package/dist/i18n/create-i18n.js.map +1 -1
  1137. package/dist/icons/Icon.cjs.map +1 -1
  1138. package/dist/icons/Icon.js.map +1 -1
  1139. package/dist/icons/IconPicker.cjs.map +1 -1
  1140. package/dist/icons/IconPicker.js.map +1 -1
  1141. package/dist/icons/IconPicker.module.cjs.map +1 -1
  1142. package/dist/icons/IconPicker.module.js.map +1 -1
  1143. package/dist/icons/IconProvider.cjs.map +1 -1
  1144. package/dist/icons/IconProvider.js.map +1 -1
  1145. package/dist/icons/alias.cjs.map +1 -1
  1146. package/dist/icons/alias.js.map +1 -1
  1147. package/dist/icons/generated/aliases.cjs.map +1 -1
  1148. package/dist/icons/generated/aliases.js.map +1 -1
  1149. package/dist/icons/generated/icon-names.cjs.map +1 -1
  1150. package/dist/icons/generated/icon-names.js.map +1 -1
  1151. package/dist/icons/generated/loaders.cjs.map +1 -1
  1152. package/dist/icons/generated/loaders.js.map +1 -1
  1153. package/dist/icons/generated/shard-00.cjs.map +1 -1
  1154. package/dist/icons/generated/shard-00.js.map +1 -1
  1155. package/dist/icons/generated/shard-01.cjs.map +1 -1
  1156. package/dist/icons/generated/shard-01.js.map +1 -1
  1157. package/dist/icons/generated/shard-02.cjs.map +1 -1
  1158. package/dist/icons/generated/shard-02.js.map +1 -1
  1159. package/dist/icons/generated/shard-03.cjs.map +1 -1
  1160. package/dist/icons/generated/shard-03.js.map +1 -1
  1161. package/dist/icons/generated/shard-04.cjs.map +1 -1
  1162. package/dist/icons/generated/shard-04.js.map +1 -1
  1163. package/dist/icons/generated/shard-05.cjs.map +1 -1
  1164. package/dist/icons/generated/shard-05.js.map +1 -1
  1165. package/dist/icons/generated/shard-06.cjs.map +1 -1
  1166. package/dist/icons/generated/shard-06.js.map +1 -1
  1167. package/dist/icons/generated/shard-07.cjs.map +1 -1
  1168. package/dist/icons/generated/shard-07.js.map +1 -1
  1169. package/dist/icons/generated/shard-08.cjs.map +1 -1
  1170. package/dist/icons/generated/shard-08.js.map +1 -1
  1171. package/dist/icons/generated/shard-09.cjs.map +1 -1
  1172. package/dist/icons/generated/shard-09.js.map +1 -1
  1173. package/dist/icons/generated/shard-10.cjs.map +1 -1
  1174. package/dist/icons/generated/shard-10.js.map +1 -1
  1175. package/dist/icons/generated/shard-11.cjs.map +1 -1
  1176. package/dist/icons/generated/shard-11.js.map +1 -1
  1177. package/dist/icons/generated/shard-12.cjs.map +1 -1
  1178. package/dist/icons/generated/shard-12.js.map +1 -1
  1179. package/dist/icons/generated/shard-13.cjs.map +1 -1
  1180. package/dist/icons/generated/shard-13.js.map +1 -1
  1181. package/dist/icons/generated/shard-14.cjs.map +1 -1
  1182. package/dist/icons/generated/shard-14.js.map +1 -1
  1183. package/dist/icons/generated/shard-15.cjs.map +1 -1
  1184. package/dist/icons/generated/shard-15.js.map +1 -1
  1185. package/dist/icons/generated/shard-16.cjs.map +1 -1
  1186. package/dist/icons/generated/shard-16.js.map +1 -1
  1187. package/dist/icons/generated/shard-17.cjs.map +1 -1
  1188. package/dist/icons/generated/shard-17.js.map +1 -1
  1189. package/dist/icons/generated/shard-18.cjs.map +1 -1
  1190. package/dist/icons/generated/shard-18.js.map +1 -1
  1191. package/dist/icons/generated/shard-19.cjs.map +1 -1
  1192. package/dist/icons/generated/shard-19.js.map +1 -1
  1193. package/dist/icons/generated/shard-20.cjs.map +1 -1
  1194. package/dist/icons/generated/shard-20.js.map +1 -1
  1195. package/dist/icons/generated/shard-21.cjs.map +1 -1
  1196. package/dist/icons/generated/shard-21.js.map +1 -1
  1197. package/dist/icons/generated/shard-22.cjs.map +1 -1
  1198. package/dist/icons/generated/shard-22.js.map +1 -1
  1199. package/dist/icons/generated/shard-23.cjs.map +1 -1
  1200. package/dist/icons/generated/shard-23.js.map +1 -1
  1201. package/dist/icons/generated/shard-24.cjs.map +1 -1
  1202. package/dist/icons/generated/shard-24.js.map +1 -1
  1203. package/dist/icons/generated/shard-25.cjs.map +1 -1
  1204. package/dist/icons/generated/shard-25.js.map +1 -1
  1205. package/dist/icons/generated/shard-26.cjs.map +1 -1
  1206. package/dist/icons/generated/shard-26.js.map +1 -1
  1207. package/dist/icons/generated/shard-27.cjs.map +1 -1
  1208. package/dist/icons/generated/shard-27.js.map +1 -1
  1209. package/dist/icons/generated/shard-28.cjs.map +1 -1
  1210. package/dist/icons/generated/shard-28.js.map +1 -1
  1211. package/dist/icons/generated/shard-29.cjs.map +1 -1
  1212. package/dist/icons/generated/shard-29.js.map +1 -1
  1213. package/dist/icons/generated/shard-30.cjs.map +1 -1
  1214. package/dist/icons/generated/shard-30.js.map +1 -1
  1215. package/dist/icons/generated/shard-31.cjs.map +1 -1
  1216. package/dist/icons/generated/shard-31.js.map +1 -1
  1217. package/dist/icons/generated/shard-32.cjs.map +1 -1
  1218. package/dist/icons/generated/shard-32.js.map +1 -1
  1219. package/dist/icons/generated/shard-33.cjs.map +1 -1
  1220. package/dist/icons/generated/shard-33.js.map +1 -1
  1221. package/dist/icons/generated/shard-34.cjs.map +1 -1
  1222. package/dist/icons/generated/shard-34.js.map +1 -1
  1223. package/dist/icons/generated/shard-35.cjs.map +1 -1
  1224. package/dist/icons/generated/shard-35.js.map +1 -1
  1225. package/dist/icons/generated/shard-36.cjs.map +1 -1
  1226. package/dist/icons/generated/shard-36.js.map +1 -1
  1227. package/dist/icons/generated/shard-37.cjs.map +1 -1
  1228. package/dist/icons/generated/shard-37.js.map +1 -1
  1229. package/dist/icons/generated/shard-38.cjs.map +1 -1
  1230. package/dist/icons/generated/shard-38.js.map +1 -1
  1231. package/dist/icons/generated/shard-39.cjs.map +1 -1
  1232. package/dist/icons/generated/shard-39.js.map +1 -1
  1233. package/dist/icons/generated/shard-40.cjs.map +1 -1
  1234. package/dist/icons/generated/shard-40.js.map +1 -1
  1235. package/dist/icons/generated/shard-41.cjs.map +1 -1
  1236. package/dist/icons/generated/shard-41.js.map +1 -1
  1237. package/dist/icons/generated/shard-42.cjs.map +1 -1
  1238. package/dist/icons/generated/shard-42.js.map +1 -1
  1239. package/dist/icons/generated/shard-43.cjs.map +1 -1
  1240. package/dist/icons/generated/shard-43.js.map +1 -1
  1241. package/dist/icons/generated/shard-44.cjs.map +1 -1
  1242. package/dist/icons/generated/shard-44.js.map +1 -1
  1243. package/dist/icons/generated/shard-45.cjs.map +1 -1
  1244. package/dist/icons/generated/shard-45.js.map +1 -1
  1245. package/dist/icons/icon-context.cjs.map +1 -1
  1246. package/dist/icons/icon-context.js.map +1 -1
  1247. package/dist/icons/is-icon-name.cjs.map +1 -1
  1248. package/dist/icons/is-icon-name.js.map +1 -1
  1249. package/dist/icons/material-symbols.cjs.map +1 -1
  1250. package/dist/icons/material-symbols.js.map +1 -1
  1251. package/dist/icons/normalize-icon-name.cjs.map +1 -1
  1252. package/dist/icons/normalize-icon-name.js.map +1 -1
  1253. package/dist/icons/shard-cache.cjs +1 -1
  1254. package/dist/icons/shard-cache.cjs.map +1 -1
  1255. package/dist/icons/shard-cache.js +2 -5
  1256. package/dist/icons/shard-cache.js.map +1 -1
  1257. package/dist/icons/use-icon.cjs.map +1 -1
  1258. package/dist/icons/use-icon.js.map +1 -1
  1259. package/dist/icons/validate-icon-name.cjs.map +1 -1
  1260. package/dist/icons/validate-icon-name.js.map +1 -1
  1261. package/dist/icons-virtual.cjs.map +1 -1
  1262. package/dist/icons-virtual.js.map +1 -1
  1263. package/dist/imaging/canvas.cjs.map +1 -1
  1264. package/dist/imaging/canvas.js.map +1 -1
  1265. package/dist/imaging/compress.cjs.map +1 -1
  1266. package/dist/imaging/compress.js.map +1 -1
  1267. package/dist/imaging/decode.cjs.map +1 -1
  1268. package/dist/imaging/decode.js.map +1 -1
  1269. package/dist/imaging/encode.cjs.map +1 -1
  1270. package/dist/imaging/encode.js.map +1 -1
  1271. package/dist/imaging/exceptions.cjs.map +1 -1
  1272. package/dist/imaging/exceptions.js.map +1 -1
  1273. package/dist/imaging/frame.cjs.map +1 -1
  1274. package/dist/imaging/frame.js.map +1 -1
  1275. package/dist/imaging/thumbnails.cjs.map +1 -1
  1276. package/dist/imaging/thumbnails.js.map +1 -1
  1277. package/dist/imaging/transform.cjs.map +1 -1
  1278. package/dist/imaging/transform.js.map +1 -1
  1279. package/dist/imaging/use-image-processing.cjs.map +1 -1
  1280. package/dist/imaging/use-image-processing.js.map +1 -1
  1281. package/dist/logger/logger.cjs.map +1 -1
  1282. package/dist/logger/logger.js.map +1 -1
  1283. package/dist/neural.cjs.map +1 -1
  1284. package/dist/neural.js.map +1 -1
  1285. package/dist/oauth/GoogleSignIn.cjs +1 -1
  1286. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  1287. package/dist/oauth/GoogleSignIn.js +6 -9
  1288. package/dist/oauth/GoogleSignIn.js.map +1 -1
  1289. package/dist/oauth/callback.cjs.map +1 -1
  1290. package/dist/oauth/callback.js.map +1 -1
  1291. package/dist/oauth/use-oauth-callback.cjs.map +1 -1
  1292. package/dist/oauth/use-oauth-callback.js.map +1 -1
  1293. package/dist/offline/conflict.cjs.map +1 -1
  1294. package/dist/offline/conflict.js.map +1 -1
  1295. package/dist/offline/create-offline-database.cjs.map +1 -1
  1296. package/dist/offline/create-offline-database.js.map +1 -1
  1297. package/dist/offline/create-offline-store.cjs +1 -1
  1298. package/dist/offline/create-offline-store.cjs.map +1 -1
  1299. package/dist/offline/create-offline-store.js +1 -5
  1300. package/dist/offline/create-offline-store.js.map +1 -1
  1301. package/dist/offline/create-offline-sync.cjs +1 -1
  1302. package/dist/offline/create-offline-sync.cjs.map +1 -1
  1303. package/dist/offline/create-offline-sync.js +9 -14
  1304. package/dist/offline/create-offline-sync.js.map +1 -1
  1305. package/dist/offline/use-offline-sync.cjs.map +1 -1
  1306. package/dist/offline/use-offline-sync.js.map +1 -1
  1307. package/dist/perf/cache-size.cjs.map +1 -1
  1308. package/dist/perf/cache-size.js.map +1 -1
  1309. package/dist/perf/device.cjs.map +1 -1
  1310. package/dist/perf/device.js.map +1 -1
  1311. package/dist/perf/format.cjs.map +1 -1
  1312. package/dist/perf/format.js.map +1 -1
  1313. package/dist/perf/profiler.cjs.map +1 -1
  1314. package/dist/perf/profiler.js.map +1 -1
  1315. package/dist/push/use-push-subscription.cjs.map +1 -1
  1316. package/dist/push/use-push-subscription.js.map +1 -1
  1317. package/dist/push/utils.cjs.map +1 -1
  1318. package/dist/push/utils.js.map +1 -1
  1319. package/dist/push/web-push-client.cjs.map +1 -1
  1320. package/dist/push/web-push-client.js.map +1 -1
  1321. package/dist/query/QueryProvider.cjs.map +1 -1
  1322. package/dist/query/QueryProvider.js.map +1 -1
  1323. package/dist/query/constants.cjs.map +1 -1
  1324. package/dist/query/constants.js.map +1 -1
  1325. package/dist/query/create-query-keys.cjs.map +1 -1
  1326. package/dist/query/create-query-keys.js.map +1 -1
  1327. package/dist/query/foreign-client-warning.cjs.map +1 -1
  1328. package/dist/query/foreign-client-warning.js.map +1 -1
  1329. package/dist/query/offline-persistence.cjs +1 -1
  1330. package/dist/query/offline-persistence.cjs.map +1 -1
  1331. package/dist/query/offline-persistence.js +2 -10
  1332. package/dist/query/offline-persistence.js.map +1 -1
  1333. package/dist/query/optimistic.cjs.map +1 -1
  1334. package/dist/query/optimistic.js.map +1 -1
  1335. package/dist/query/pagination.cjs.map +1 -1
  1336. package/dist/query/pagination.js.map +1 -1
  1337. package/dist/query/retry-policy.cjs.map +1 -1
  1338. package/dist/query/retry-policy.js.map +1 -1
  1339. package/dist/query/use-cursor-query.cjs.map +1 -1
  1340. package/dist/query/use-cursor-query.js.map +1 -1
  1341. package/dist/query/use-offline-mutation.cjs.map +1 -1
  1342. package/dist/query/use-offline-mutation.js.map +1 -1
  1343. package/dist/query/use-paginated-query.cjs.map +1 -1
  1344. package/dist/query/use-paginated-query.js.map +1 -1
  1345. package/dist/router/AppRouter.cjs.map +1 -1
  1346. package/dist/router/AppRouter.js.map +1 -1
  1347. package/dist/router/RouteGuard.cjs.map +1 -1
  1348. package/dist/router/RouteGuard.js.map +1 -1
  1349. package/dist/router/index.js +2 -2
  1350. package/dist/share/share-or-download.cjs.map +1 -1
  1351. package/dist/share/share-or-download.js.map +1 -1
  1352. package/dist/share/share.cjs.map +1 -1
  1353. package/dist/share/share.js.map +1 -1
  1354. package/dist/sse/create-event-stream.cjs.map +1 -1
  1355. package/dist/sse/create-event-stream.js.map +1 -1
  1356. package/dist/sse/use-event-stream.cjs.map +1 -1
  1357. package/dist/sse/use-event-stream.js.map +1 -1
  1358. package/dist/store/create-selectors.cjs.map +1 -1
  1359. package/dist/store/create-selectors.js.map +1 -1
  1360. package/dist/store/create-store.cjs.map +1 -1
  1361. package/dist/store/create-store.js.map +1 -1
  1362. package/dist/sw/background-sync.cjs +1 -1
  1363. package/dist/sw/background-sync.cjs.map +1 -1
  1364. package/dist/sw/background-sync.js +32 -31
  1365. package/dist/sw/background-sync.js.map +1 -1
  1366. package/dist/sw/cache-inspect.cjs.map +1 -1
  1367. package/dist/sw/cache-inspect.js.map +1 -1
  1368. package/dist/sw/cache.cjs +1 -1
  1369. package/dist/sw/cache.cjs.map +1 -1
  1370. package/dist/sw/cache.js +2 -6
  1371. package/dist/sw/cache.js.map +1 -1
  1372. package/dist/sw/create-push-handler.cjs.map +1 -1
  1373. package/dist/sw/create-push-handler.js.map +1 -1
  1374. package/dist/sw/credential-headers.cjs.map +1 -1
  1375. package/dist/sw/credential-headers.js.map +1 -1
  1376. package/dist/sw/periodic-sync.cjs.map +1 -1
  1377. package/dist/sw/periodic-sync.js.map +1 -1
  1378. package/dist/sw/register-service-worker.cjs.map +1 -1
  1379. package/dist/sw/register-service-worker.js.map +1 -1
  1380. package/dist/sw/session-data.cjs.map +1 -1
  1381. package/dist/sw/session-data.js.map +1 -1
  1382. package/dist/sw.d.ts +46 -8
  1383. package/dist/tabular/assets.cjs.map +1 -1
  1384. package/dist/tabular/assets.js.map +1 -1
  1385. package/dist/tabular/cache.cjs.map +1 -1
  1386. package/dist/tabular/cache.js.map +1 -1
  1387. package/dist/tabular/compact.cjs.map +1 -1
  1388. package/dist/tabular/compact.js.map +1 -1
  1389. package/dist/tabular/exceptions.cjs.map +1 -1
  1390. package/dist/tabular/exceptions.js.map +1 -1
  1391. package/dist/tabular/manifest.cjs.map +1 -1
  1392. package/dist/tabular/manifest.js.map +1 -1
  1393. package/dist/tabular/predictor.cjs.map +1 -1
  1394. package/dist/tabular/predictor.js.map +1 -1
  1395. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  1396. package/dist/tabular/use-tabular-predictor.js.map +1 -1
  1397. package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
  1398. package/dist/telemetry/TelemetryProvider.js.map +1 -1
  1399. package/dist/telemetry/app-error-adapter.cjs.map +1 -1
  1400. package/dist/telemetry/app-error-adapter.js.map +1 -1
  1401. package/dist/telemetry/app-error-queue.cjs.map +1 -1
  1402. package/dist/telemetry/app-error-queue.js.map +1 -1
  1403. package/dist/telemetry/app-error-reporter.cjs +1 -1
  1404. package/dist/telemetry/app-error-reporter.cjs.map +1 -1
  1405. package/dist/telemetry/app-error-reporter.js +1 -1
  1406. package/dist/telemetry/app-error-reporter.js.map +1 -1
  1407. package/dist/telemetry/app-error-schema.cjs.map +1 -1
  1408. package/dist/telemetry/app-error-schema.js.map +1 -1
  1409. package/dist/telemetry/app-error-transport.cjs.map +1 -1
  1410. package/dist/telemetry/app-error-transport.js.map +1 -1
  1411. package/dist/telemetry/console-adapter.cjs.map +1 -1
  1412. package/dist/telemetry/console-adapter.js.map +1 -1
  1413. package/dist/telemetry/describe-app-error.cjs.map +1 -1
  1414. package/dist/telemetry/describe-app-error.js.map +1 -1
  1415. package/dist/telemetry/posthog-adapter.cjs +1 -1
  1416. package/dist/telemetry/posthog-adapter.cjs.map +1 -1
  1417. package/dist/telemetry/posthog-adapter.js +1 -5
  1418. package/dist/telemetry/posthog-adapter.js.map +1 -1
  1419. package/dist/telemetry/sentry-adapter.cjs.map +1 -1
  1420. package/dist/telemetry/sentry-adapter.js.map +1 -1
  1421. package/dist/tempest-react-sdk.cjs +1 -1
  1422. package/dist/tempest-react-sdk.d.ts +448 -15
  1423. package/dist/tempest-react-sdk.js +119 -119
  1424. package/dist/testing/create-mock-handlers.cjs.map +1 -1
  1425. package/dist/testing/create-mock-handlers.js.map +1 -1
  1426. package/dist/testing.js +1 -2
  1427. package/dist/theme/ThemeProvider.cjs.map +1 -1
  1428. package/dist/theme/ThemeProvider.js.map +1 -1
  1429. package/dist/theme/apply-theme.cjs.map +1 -1
  1430. package/dist/theme/apply-theme.js.map +1 -1
  1431. package/dist/theme/color.cjs.map +1 -1
  1432. package/dist/theme/color.js.map +1 -1
  1433. package/dist/theme/create-theme.cjs.map +1 -1
  1434. package/dist/theme/create-theme.js.map +1 -1
  1435. package/dist/theme/data-viz-ramps.cjs.map +1 -1
  1436. package/dist/theme/data-viz-ramps.js.map +1 -1
  1437. package/dist/theme/initial-theme.cjs.map +1 -1
  1438. package/dist/theme/initial-theme.js.map +1 -1
  1439. package/dist/theme/inverse-render.cjs.map +1 -1
  1440. package/dist/theme/inverse-render.js.map +1 -1
  1441. package/dist/theme/inverse-restore.cjs.map +1 -1
  1442. package/dist/theme/inverse-restore.js.map +1 -1
  1443. package/dist/theme/inverse-surface.cjs.map +1 -1
  1444. package/dist/theme/inverse-surface.js.map +1 -1
  1445. package/dist/theme/status-tokens.cjs.map +1 -1
  1446. package/dist/theme/status-tokens.js.map +1 -1
  1447. package/dist/theme/theme-presets.cjs.map +1 -1
  1448. package/dist/theme/theme-presets.js.map +1 -1
  1449. package/dist/utils/absent.cjs.map +1 -1
  1450. package/dist/utils/absent.js.map +1 -1
  1451. package/dist/utils/arrays.cjs.map +1 -1
  1452. package/dist/utils/arrays.js.map +1 -1
  1453. package/dist/utils/base64.cjs.map +1 -1
  1454. package/dist/utils/base64.js.map +1 -1
  1455. package/dist/utils/cn.cjs.map +1 -1
  1456. package/dist/utils/cn.js.map +1 -1
  1457. package/dist/utils/compare-values.cjs.map +1 -1
  1458. package/dist/utils/compare-values.js.map +1 -1
  1459. package/dist/utils/compressed-storage.cjs.map +1 -1
  1460. package/dist/utils/compressed-storage.js.map +1 -1
  1461. package/dist/utils/csv.cjs +3 -3
  1462. package/dist/utils/csv.cjs.map +1 -1
  1463. package/dist/utils/csv.js +11 -10
  1464. package/dist/utils/csv.js.map +1 -1
  1465. package/dist/utils/dev-mode.cjs.map +1 -1
  1466. package/dist/utils/dev-mode.js.map +1 -1
  1467. package/dist/utils/duplicate-instance.cjs.map +1 -1
  1468. package/dist/utils/duplicate-instance.js.map +1 -1
  1469. package/dist/utils/format.cjs.map +1 -1
  1470. package/dist/utils/format.js.map +1 -1
  1471. package/dist/utils/functions.cjs +1 -1
  1472. package/dist/utils/functions.cjs.map +1 -1
  1473. package/dist/utils/functions.js +1 -1
  1474. package/dist/utils/functions.js.map +1 -1
  1475. package/dist/utils/guards.cjs.map +1 -1
  1476. package/dist/utils/guards.js.map +1 -1
  1477. package/dist/utils/ids.cjs.map +1 -1
  1478. package/dist/utils/ids.js.map +1 -1
  1479. package/dist/utils/intl-cache.cjs.map +1 -1
  1480. package/dist/utils/intl-cache.js.map +1 -1
  1481. package/dist/utils/json-frame.cjs.map +1 -1
  1482. package/dist/utils/json-frame.js.map +1 -1
  1483. package/dist/utils/numbers.cjs.map +1 -1
  1484. package/dist/utils/numbers.js.map +1 -1
  1485. package/dist/utils/objects.cjs.map +1 -1
  1486. package/dist/utils/objects.js.map +1 -1
  1487. package/dist/{telemetry/app-error-owner.cjs → utils/owner-fingerprint.cjs} +2 -2
  1488. package/dist/utils/owner-fingerprint.cjs.map +1 -0
  1489. package/dist/{telemetry/app-error-owner.js → utils/owner-fingerprint.js} +3 -3
  1490. package/dist/utils/owner-fingerprint.js.map +1 -0
  1491. package/dist/utils/promises.cjs.map +1 -1
  1492. package/dist/utils/promises.js.map +1 -1
  1493. package/dist/utils/relative-time.cjs.map +1 -1
  1494. package/dist/utils/relative-time.js.map +1 -1
  1495. package/dist/utils/safe-url.cjs.map +1 -1
  1496. package/dist/utils/safe-url.js.map +1 -1
  1497. package/dist/utils/schema-like.cjs.map +1 -1
  1498. package/dist/utils/schema-like.js.map +1 -1
  1499. package/dist/utils/storage.cjs +1 -1
  1500. package/dist/utils/storage.cjs.map +1 -1
  1501. package/dist/utils/storage.js +2 -2
  1502. package/dist/utils/storage.js.map +1 -1
  1503. package/dist/utils/strings.cjs.map +1 -1
  1504. package/dist/utils/strings.js.map +1 -1
  1505. package/dist/utils/xlsx.cjs.map +1 -1
  1506. package/dist/utils/xlsx.js.map +1 -1
  1507. package/dist/vision/core/canvas.cjs.map +1 -1
  1508. package/dist/vision/core/canvas.js.map +1 -1
  1509. package/dist/vision/core/dtypes.cjs.map +1 -1
  1510. package/dist/vision/core/dtypes.js.map +1 -1
  1511. package/dist/vision/core/exceptions.cjs.map +1 -1
  1512. package/dist/vision/core/exceptions.js.map +1 -1
  1513. package/dist/vision/core/graph.cjs.map +1 -1
  1514. package/dist/vision/core/graph.js.map +1 -1
  1515. package/dist/vision/core/metadata.cjs +1 -1
  1516. package/dist/vision/core/metadata.cjs.map +1 -1
  1517. package/dist/vision/core/metadata.js +9 -26
  1518. package/dist/vision/core/metadata.js.map +1 -1
  1519. package/dist/vision/core/providers.cjs.map +1 -1
  1520. package/dist/vision/core/providers.js.map +1 -1
  1521. package/dist/vision/core/session.cjs.map +1 -1
  1522. package/dist/vision/core/session.js.map +1 -1
  1523. package/dist/vision/core/timing.cjs.map +1 -1
  1524. package/dist/vision/core/timing.js.map +1 -1
  1525. package/dist/vision/fusion.cjs.map +1 -1
  1526. package/dist/vision/fusion.js.map +1 -1
  1527. package/dist/vision/index.cjs.map +1 -1
  1528. package/dist/vision/index.js.map +1 -1
  1529. package/dist/vision/io/image.cjs.map +1 -1
  1530. package/dist/vision/io/image.js.map +1 -1
  1531. package/dist/vision/labels.cjs.map +1 -1
  1532. package/dist/vision/labels.js.map +1 -1
  1533. package/dist/vision/luminance.cjs.map +1 -1
  1534. package/dist/vision/luminance.js.map +1 -1
  1535. package/dist/vision/normalization.cjs.map +1 -1
  1536. package/dist/vision/normalization.js.map +1 -1
  1537. package/dist/vision/postprocess/classification.cjs.map +1 -1
  1538. package/dist/vision/postprocess/classification.js.map +1 -1
  1539. package/dist/vision/postprocess/detection.cjs.map +1 -1
  1540. package/dist/vision/postprocess/detection.js.map +1 -1
  1541. package/dist/vision/postprocess/segmentation.cjs.map +1 -1
  1542. package/dist/vision/postprocess/segmentation.js.map +1 -1
  1543. package/dist/vision/preprocess/image.cjs.map +1 -1
  1544. package/dist/vision/preprocess/image.js.map +1 -1
  1545. package/dist/vision/preprocess/pipeline.cjs.map +1 -1
  1546. package/dist/vision/preprocess/pipeline.js.map +1 -1
  1547. package/dist/vision/results.cjs.map +1 -1
  1548. package/dist/vision/results.js.map +1 -1
  1549. package/dist/vision/tasks/base.cjs.map +1 -1
  1550. package/dist/vision/tasks/base.js.map +1 -1
  1551. package/dist/vision/tasks/classifier.cjs.map +1 -1
  1552. package/dist/vision/tasks/classifier.js.map +1 -1
  1553. package/dist/vision/tasks/detectClassify.cjs.map +1 -1
  1554. package/dist/vision/tasks/detectClassify.js.map +1 -1
  1555. package/dist/vision/tasks/detector.cjs.map +1 -1
  1556. package/dist/vision/tasks/detector.js.map +1 -1
  1557. package/dist/vision/tasks/segmenter.cjs.map +1 -1
  1558. package/dist/vision/tasks/segmenter.js.map +1 -1
  1559. package/dist/vision/types.cjs.map +1 -1
  1560. package/dist/vision/types.js.map +1 -1
  1561. package/dist/vision/use-camera-stream.cjs +1 -1
  1562. package/dist/vision/use-camera-stream.cjs.map +1 -1
  1563. package/dist/vision/use-camera-stream.js +3 -9
  1564. package/dist/vision/use-camera-stream.js.map +1 -1
  1565. package/dist/vision/use-live-luminance.cjs +1 -1
  1566. package/dist/vision/use-live-luminance.cjs.map +1 -1
  1567. package/dist/vision/use-live-luminance.js +1 -5
  1568. package/dist/vision/use-live-luminance.js.map +1 -1
  1569. package/dist/vite/base-url.cjs.map +1 -1
  1570. package/dist/vite/base-url.js.map +1 -1
  1571. package/dist/vite/create-vite-config.cjs.map +1 -1
  1572. package/dist/vite/create-vite-config.js.map +1 -1
  1573. package/dist/vite/narrow-tokens.cjs.map +1 -1
  1574. package/dist/vite/narrow-tokens.js.map +1 -1
  1575. package/dist/vite/tempest-csp.cjs +2 -2
  1576. package/dist/vite/tempest-csp.cjs.map +1 -1
  1577. package/dist/vite/tempest-csp.js +69 -66
  1578. package/dist/vite/tempest-csp.js.map +1 -1
  1579. package/dist/vite/tempest-icons.cjs.map +1 -1
  1580. package/dist/vite/tempest-icons.js.map +1 -1
  1581. package/dist/vite/tempest-pwa-dev-sw.cjs +1 -1
  1582. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  1583. package/dist/vite/tempest-pwa-dev-sw.js +9 -16
  1584. package/dist/vite/tempest-pwa-dev-sw.js.map +1 -1
  1585. package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
  1586. package/dist/vite/tempest-pwa-icons.js.map +1 -1
  1587. package/dist/vite/tempest-pwa-manifest.cjs.map +1 -1
  1588. package/dist/vite/tempest-pwa-manifest.js.map +1 -1
  1589. package/dist/vite/tempest-styles.cjs.map +1 -1
  1590. package/dist/vite/tempest-styles.js.map +1 -1
  1591. package/dist/vite/tempest-vitest.cjs.map +1 -1
  1592. package/dist/vite/tempest-vitest.js.map +1 -1
  1593. package/dist/vite.d.ts +5 -3
  1594. package/dist/webrtc/link-stats.cjs.map +1 -1
  1595. package/dist/webrtc/link-stats.js.map +1 -1
  1596. package/dist/webrtc/mesh-quality.cjs.map +1 -1
  1597. package/dist/webrtc/mesh-quality.js.map +1 -1
  1598. package/dist/webrtc/opus-sdp.cjs.map +1 -1
  1599. package/dist/webrtc/opus-sdp.js.map +1 -1
  1600. package/dist/webrtc/peer-link.cjs +1 -1
  1601. package/dist/webrtc/peer-link.cjs.map +1 -1
  1602. package/dist/webrtc/peer-link.js +2 -5
  1603. package/dist/webrtc/peer-link.js.map +1 -1
  1604. package/dist/webrtc/peer-mesh.cjs +1 -1
  1605. package/dist/webrtc/peer-mesh.cjs.map +1 -1
  1606. package/dist/webrtc/peer-mesh.js +8 -24
  1607. package/dist/webrtc/peer-mesh.js.map +1 -1
  1608. package/dist/webrtc/sender-bitrate.cjs.map +1 -1
  1609. package/dist/webrtc/sender-bitrate.js.map +1 -1
  1610. package/dist/webrtc/use-link-stats.cjs.map +1 -1
  1611. package/dist/webrtc/use-link-stats.js.map +1 -1
  1612. package/dist/ws/create-web-socket.cjs +1 -1
  1613. package/dist/ws/create-web-socket.cjs.map +1 -1
  1614. package/dist/ws/create-web-socket.js +4 -22
  1615. package/dist/ws/create-web-socket.js.map +1 -1
  1616. package/dist/ws/resilience.cjs.map +1 -1
  1617. package/dist/ws/resilience.js.map +1 -1
  1618. package/dist/ws/use-web-socket.cjs.map +1 -1
  1619. package/dist/ws/use-web-socket.js.map +1 -1
  1620. package/package.json +9 -6
  1621. package/template/package.json +1 -1
  1622. package/dist/telemetry/app-error-owner.cjs.map +0 -1
  1623. package/dist/telemetry/app-error-owner.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"color.cjs","names":[],"sources":["../../src/theme/color.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — OKLCH ↔ sRGB with the gamut mapping in between: the\n * transfer function, the LMS matrices, the chroma search that finds the nearest in-\n * gamut colour and the contrast ratio used to check it. Matrices split across files\n * are matrices that get edited one half at a time.\n */\n/**\n * Color math behind {@link createTheme} — OKLab/OKLCH conversions, tint scale\n * generation and WCAG contrast picking.\n *\n * Everything here is pure and dependency-free: the SDK generates brand ramps at\n * runtime in the browser, so a color library would be a disproportionate cost\n * for ~150 lines of well-specified math. OKLCH is used instead of HSL because\n * HSL lightness is not perceptual — an HSL ramp of a yellow and of a blue at the\n * same `L` read as wildly different brightness, which is exactly what breaks a\n * generated palette.\n */\n\n/** A color in the OKLCH space: perceptual lightness, chroma and hue. */\nexport interface Oklch {\n /** Perceptual lightness, `0` (black) to `1` (white). */\n l: number;\n /** Chroma (colorfulness). `0` is gray; sRGB rarely exceeds `~0.37`. */\n c: number;\n /** Hue angle in degrees, `0`–`360`. */\n h: number;\n}\n\n/** The ten steps of a Tempest tint scale, lightest to darkest. */\nexport type ScaleStep = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;\n\n/** A generated tint scale, keyed by step. */\nexport type ColorScale = Record<ScaleStep, string>;\n\nconst SCALE_STEPS: ScaleStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\n\n/**\n * Target lightness per step for a **brand** ramp in light mode.\n *\n * These are the measured OKLCH lightnesses of the hand-written `--tempest-primary-*`\n * scale in `colors.css`, so a generated brand ramp lands in the same visual range\n * as the built-in one instead of merely near it.\n */\nconst LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.966,\n 100: 0.923,\n 200: 0.844,\n 300: 0.743,\n 400: 0.642,\n 500: 0.563,\n 600: 0.48,\n 700: 0.391,\n 800: 0.325,\n 900: 0.251,\n};\n\n/**\n * Target lightness per step for a **neutral** ramp in light mode — measured from\n * the hand-written `--tempest-gray-*` scale.\n *\n * Deliberately **wider** than the brand curve at both ends (`0.982` → `0.210` vs\n * `0.966` → `0.251`): a neutral carries surfaces that must read as near-white and\n * text that must read as near-black, and the pair `text-muted` on `surface-3` has\n * to clear AA. Reusing the brand curve for neutrals is what dropped that pair to\n * 3.5:1 and made the browser axe sweep fail on every generated theme.\n */\nconst NEUTRAL_LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.982,\n 100: 0.963,\n 200: 0.927,\n 300: 0.872,\n 400: 0.71,\n 500: 0.544,\n 600: 0.442,\n 700: 0.369,\n 800: 0.278,\n 900: 0.21,\n};\n\n/**\n * Neutral ramp for dark mode, measured from the `[data-tempest-theme=\"dark\"]`\n * surface/text tokens: `50` is the page background and `900` is text-grade.\n */\nconst NEUTRAL_DARK_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.159,\n 100: 0.205,\n 200: 0.254,\n 300: 0.314,\n 400: 0.381,\n 500: 0.5,\n 600: 0.571,\n 700: 0.762,\n 800: 0.86,\n 900: 0.964,\n};\n\n/**\n * Target lightness for a dark-theme ramp — the ramp is **inverted**: `50` is the\n * darkest tint (a surface) and `900` the lightest (text-grade), matching the\n * `[data-tempest-theme=\"dark\"]` block in `colors.css`.\n */\nconst DARK_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.238,\n 100: 0.288,\n 200: 0.362,\n 300: 0.452,\n 400: 0.544,\n 500: 0.632,\n 600: 0.712,\n 700: 0.788,\n 800: 0.862,\n 900: 0.928,\n};\n\n/**\n * Chroma multiplier per step, relative to the input color's chroma.\n *\n * Peaks around `500`–`600` and falls off at both ends: near-white and near-black\n * tints hold very little chroma before they look muddy or leave the sRGB gamut.\n */\nconst CHROMA_CURVE: Record<ScaleStep, number> = {\n 50: 0.18,\n 100: 0.34,\n 200: 0.6,\n 300: 0.82,\n 400: 0.95,\n 500: 1,\n 600: 0.98,\n 700: 0.88,\n 800: 0.74,\n 900: 0.58,\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Expand `#abc` to `#aabbcc` and normalize to a lowercase 6-digit hex. */\nfunction normalizeHex(hex: string): string {\n const raw = hex.trim().replace(/^#/, \"\");\n const expanded =\n raw.length === 3 || raw.length === 4\n ? raw\n .slice(0, 3)\n .split(\"\")\n .map((char) => char + char)\n .join(\"\")\n : raw.slice(0, 6);\n if (!/^[0-9a-fA-F]{6}$/.test(expanded)) {\n throw new Error(`Invalid hex color: \"${hex}\"`);\n }\n return `#${expanded.toLowerCase()}`;\n}\n\n/** Parse a hex color into sRGB channels in the `0`–`1` range. */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalized = normalizeHex(hex).slice(1);\n return {\n r: parseInt(normalized.slice(0, 2), 16) / 255,\n g: parseInt(normalized.slice(2, 4), 16) / 255,\n b: parseInt(normalized.slice(4, 6), 16) / 255,\n };\n}\n\n/** Serialize sRGB channels (`0`–`1`, clamped) back to a `#rrggbb` string. */\nexport function rgbToHex(r: number, g: number, b: number): string {\n const channel = (value: number): string =>\n Math.round(clamp(value, 0, 1) * 255)\n .toString(16)\n .padStart(2, \"0\");\n return `#${channel(r)}${channel(g)}${channel(b)}`;\n}\n\nfunction srgbToLinear(channel: number): number {\n return channel <= 0.04045 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);\n}\n\nfunction linearToSrgb(channel: number): number {\n return channel <= 0.0031308 ? channel * 12.92 : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;\n}\n\n/** Convert a hex color to OKLCH. */\nexport function hexToOklch(hex: string): Oklch {\n const { r, g, b } = hexToRgb(hex);\n const lr = srgbToLinear(r);\n const lg = srgbToLinear(g);\n const lb = srgbToLinear(b);\n\n const long = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n const medium = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n const short = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n\n const l = 0.2104542553 * long + 0.793617785 * medium - 0.0040720468 * short;\n const a = 1.9779984951 * long - 2.428592205 * medium + 0.4505937099 * short;\n const bAxis = 0.0259040371 * long + 0.7827717662 * medium - 0.808675766 * short;\n\n const c = Math.sqrt(a * a + bAxis * bAxis);\n const hue = c < 1e-6 ? 0 : (Math.atan2(bAxis, a) * 180) / Math.PI;\n\n return { l, c, h: hue < 0 ? hue + 360 : hue };\n}\n\n/** Convert OKLCH to linear-light sRGB, without gamut clamping. */\nfunction oklchToLinearRgb({ l, c, h }: Oklch): { r: number; g: number; b: number } {\n const hRad = (h * Math.PI) / 180;\n const a = Math.cos(hRad) * c;\n const bAxis = Math.sin(hRad) * c;\n\n const long = (l + 0.3963377774 * a + 0.2158037573 * bAxis) ** 3;\n const medium = (l - 0.1055613458 * a - 0.0638541728 * bAxis) ** 3;\n const short = (l - 0.0894841775 * a - 1.291485548 * bAxis) ** 3;\n\n return {\n r: 4.0767416621 * long - 3.3077115913 * medium + 0.2309699292 * short,\n g: -1.2684380046 * long + 2.6097574011 * medium - 0.3413193965 * short,\n b: -0.0041960863 * long - 0.7034186147 * medium + 1.707614701 * short,\n };\n}\n\nfunction inGamut({ r, g, b }: { r: number; g: number; b: number }): boolean {\n const epsilon = 1e-4;\n return (\n r >= -epsilon &&\n r <= 1 + epsilon &&\n g >= -epsilon &&\n g <= 1 + epsilon &&\n b >= -epsilon &&\n b <= 1 + epsilon\n );\n}\n\n/**\n * Convert OKLCH to a hex color, reducing chroma until the result fits sRGB.\n *\n * Lightness and hue are preserved: desaturating is far less noticeable than\n * shifting either of them, and a naive channel clamp would do both.\n */\nexport function oklchToHex(color: Oklch): string {\n let chroma = Math.max(0, color.c);\n let rgb = oklchToLinearRgb({ ...color, c: chroma });\n\n for (let i = 0; i < 24 && !inGamut(rgb); i += 1) {\n chroma *= 0.9;\n rgb = oklchToLinearRgb({ ...color, c: chroma });\n }\n\n return rgbToHex(linearToSrgb(rgb.r), linearToSrgb(rgb.g), linearToSrgb(rgb.b));\n}\n\n/** Options for {@link createColorScale}. */\nexport interface ColorScaleOptions {\n /**\n * Pin step `500` to the input color's exact lightness. Default `true`.\n *\n * Right for a **brand** color: the hex a designer hands over is the one the\n * buttons must be. Wrong for a **neutral**: nobody checks that `gray-500` is\n * exactly the input, while everybody notices that a surface stopped being\n * near-white — anchoring rescales both halves around the input and compresses\n * exactly the range a neutral needs wide. With `false`, the ramp keeps the\n * tuned lightness curve and the input only contributes hue and chroma (a warm\n * or cool neutral, as asked).\n */\n anchor?: boolean;\n /**\n * Use the neutral lightness curve instead of the brand one. Default `false`.\n *\n * The neutral curve is wider at both ends, which is what keeps\n * `text-muted`-on-`surface-3` above AA. Implies the ramp is meant for\n * surfaces, borders and text rather than for an action color.\n */\n neutral?: boolean;\n}\n\n/**\n * Build a ten-step tint scale from a single color.\n *\n * The input color's hue is kept throughout and its chroma sets the intensity of\n * the whole ramp, so a muted brand color yields a muted scale instead of being\n * \"corrected\" into something the brand never approved.\n *\n * @param hex - Any hex color (`#abc` or `#aabbcc`), the intended `500` step.\n * @param mode - `\"light\"` for a light→dark ramp, `\"dark\"` for the inverted ramp\n * used under `[data-tempest-theme=\"dark\"]`.\n * @param options - See {@link ColorScaleOptions}.\n */\nexport function createColorScale(\n hex: string,\n mode: \"light\" | \"dark\" = \"light\",\n options: ColorScaleOptions = {},\n): ColorScale {\n const base = hexToOklch(hex);\n const targets = options.neutral\n ? mode === \"dark\"\n ? NEUTRAL_DARK_LIGHTNESS\n : NEUTRAL_LIGHT_LIGHTNESS\n : mode === \"dark\"\n ? DARK_LIGHTNESS\n : LIGHT_LIGHTNESS;\n const lightness =\n options.anchor === false ? targets : anchorLightnessAt500(targets, base.l, mode);\n const scale = {} as ColorScale;\n\n for (const step of SCALE_STEPS) {\n scale[step] = oklchToHex({\n l: lightness[step],\n c: base.c * CHROMA_CURVE[step],\n h: base.h,\n });\n }\n\n return scale;\n}\n\n/** Widest lightness band a generated ramp may span, so both ends stay usable. */\nconst LIGHTNESS_CEILING = 0.985;\nconst LIGHTNESS_FLOOR = 0.12;\n\n/**\n * Re-anchor a lightness ramp so step `500` lands on the brand color exactly.\n *\n * Without this, `500` is forced onto the ramp's own target lightness: a brand\n * `#7c3aed` came back as `#9161fe` — same hue, same chroma, *re-lightened*. It\n * looks fine in isolation and is wrong anyway, because the one color a designer\n * hands over is the one the buttons must actually be.\n *\n * Each half of the ramp is scaled independently around the anchor, so the shape\n * of the original curve survives and the ramp stays monotonic even for a very\n * light brand (yellow) or a very dark one (navy) — those simply get a shorter\n * run on the crowded side.\n *\n * @param targets - The default per-step lightness for this scheme.\n * @param anchor - Lightness of the brand color, used verbatim at step `500`.\n * @param mode - `\"dark\"` inverts which side of the ramp is the light one.\n */\nfunction anchorLightnessAt500(\n targets: Record<ScaleStep, number>,\n anchor: number,\n mode: \"light\" | \"dark\",\n): Record<ScaleStep, number> {\n const anchored = {} as Record<ScaleStep, number>;\n const base = targets[500];\n const lightEnd = mode === \"dark\" ? targets[900] : targets[50];\n const darkEnd = mode === \"dark\" ? targets[50] : targets[900];\n\n const top = Math.min(LIGHTNESS_CEILING, Math.max(lightEnd, anchor + 0.05));\n const bottom = Math.max(LIGHTNESS_FLOOR, Math.min(darkEnd, anchor - 0.05));\n\n for (const step of SCALE_STEPS) {\n const target = targets[step];\n if (target === base) {\n anchored[step] = anchor;\n } else if (target > base) {\n const ratio = (target - base) / (lightEnd - base);\n anchored[step] = anchor + ratio * (top - anchor);\n } else {\n const ratio = (base - target) / (base - darkEnd);\n anchored[step] = anchor - ratio * (anchor - bottom);\n }\n }\n\n return anchored;\n}\n\n/** WCAG 2.x relative luminance of a hex color. */\nexport function relativeLuminance(hex: string): number {\n const { r, g, b } = hexToRgb(hex);\n return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);\n}\n\n/** WCAG 2.x contrast ratio between two hex colors, from `1` to `21`. */\nexport function contrastRatio(a: string, b: string): number {\n const la = relativeLuminance(a);\n const lb = relativeLuminance(b);\n const lighter = Math.max(la, lb);\n const darker = Math.min(la, lb);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/**\n * Pick the readable foreground for a background, by contrast ratio.\n *\n * Used for `--tempest-primary-foreground`: a generated brand color can land\n * anywhere on the lightness axis, and hardcoding white would silently produce\n * unreadable buttons for light brands (yellow, lime, cyan).\n */\nexport function readableForeground(\n background: string,\n light = \"#ffffff\",\n dark = \"#101828\",\n): string {\n return contrastRatio(background, light) >= contrastRatio(background, dark) ? light : dark;\n}\n\n/** Format a hex color as `rgb(r g b / alpha)`, for focus rings and overlays. */\nexport function hexToRgbaString(hex: string, alpha: number): string {\n const { r, g, b } = hexToRgb(hex);\n const channel = (value: number): number => Math.round(clamp(value, 0, 1) * 255);\n return `rgb(${channel(r)} ${channel(g)} ${channel(b)} / ${clamp(alpha, 0, 1)})`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"color.cjs","names":["SCALE_STEPS","LIGHT_LIGHTNESS","NEUTRAL_LIGHT_LIGHTNESS","NEUTRAL_DARK_LIGHTNESS","DARK_LIGHTNESS","CHROMA_CURVE","clamp","max","min","value","normalizeHex","raw","hex","expanded","char","hexToRgb","normalized","rgbToHex","channel","r","g","b","srgbToLinear","linearToSrgb","hexToOklch","lr","lg","lb","long","medium","short","l","a","bAxis","c","hue","oklchToLinearRgb","hRad","h","inGamut","oklchToHex","chroma","color","rgb","i","createColorScale","base","targets","options","mode","lightness","anchorLightnessAt500","scale","step","LIGHTNESS_CEILING","LIGHTNESS_FLOOR","anchored","lightEnd","darkEnd","top","anchor","bottom","target","relativeLuminance","contrastRatio","la","lighter","darker","readableForeground","background","light","dark","hexToRgbaString","alpha"],"sources":["../../src/theme/color.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — OKLCH ↔ sRGB with the gamut mapping in between: the\n * transfer function, the LMS matrices, the chroma search that finds the nearest in-\n * gamut colour and the contrast ratio used to check it. Matrices split across files\n * are matrices that get edited one half at a time.\n */\n/**\n * Color math behind {@link createTheme} — OKLab/OKLCH conversions, tint scale\n * generation and WCAG contrast picking.\n *\n * Everything here is pure and dependency-free: the SDK generates brand ramps at\n * runtime in the browser, so a color library would be a disproportionate cost\n * for ~150 lines of well-specified math. OKLCH is used instead of HSL because\n * HSL lightness is not perceptual — an HSL ramp of a yellow and of a blue at the\n * same `L` read as wildly different brightness, which is exactly what breaks a\n * generated palette.\n */\n\n/** A color in the OKLCH space: perceptual lightness, chroma and hue. */\nexport interface Oklch {\n /** Perceptual lightness, `0` (black) to `1` (white). */\n l: number;\n /** Chroma (colorfulness). `0` is gray; sRGB rarely exceeds `~0.37`. */\n c: number;\n /** Hue angle in degrees, `0`–`360`. */\n h: number;\n}\n\n/** The ten steps of a Tempest tint scale, lightest to darkest. */\nexport type ScaleStep = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;\n\n/** A generated tint scale, keyed by step. */\nexport type ColorScale = Record<ScaleStep, string>;\n\nconst SCALE_STEPS: ScaleStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\n\n/**\n * Target lightness per step for a **brand** ramp in light mode.\n *\n * These are the measured OKLCH lightnesses of the hand-written `--tempest-primary-*`\n * scale in `colors.css`, so a generated brand ramp lands in the same visual range\n * as the built-in one instead of merely near it.\n */\nconst LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.966,\n 100: 0.923,\n 200: 0.844,\n 300: 0.743,\n 400: 0.642,\n 500: 0.563,\n 600: 0.48,\n 700: 0.391,\n 800: 0.325,\n 900: 0.251,\n};\n\n/**\n * Target lightness per step for a **neutral** ramp in light mode — measured from\n * the hand-written `--tempest-gray-*` scale.\n *\n * Deliberately **wider** than the brand curve at both ends (`0.982` → `0.210` vs\n * `0.966` → `0.251`): a neutral carries surfaces that must read as near-white and\n * text that must read as near-black, and the pair `text-muted` on `surface-3` has\n * to clear AA. Reusing the brand curve for neutrals is what dropped that pair to\n * 3.5:1 and made the browser axe sweep fail on every generated theme.\n */\nconst NEUTRAL_LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.982,\n 100: 0.963,\n 200: 0.927,\n 300: 0.872,\n 400: 0.71,\n 500: 0.544,\n 600: 0.442,\n 700: 0.369,\n 800: 0.278,\n 900: 0.21,\n};\n\n/**\n * Neutral ramp for dark mode, measured from the `[data-tempest-theme=\"dark\"]`\n * surface/text tokens: `50` is the page background and `900` is text-grade.\n */\nconst NEUTRAL_DARK_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.159,\n 100: 0.205,\n 200: 0.254,\n 300: 0.314,\n 400: 0.381,\n 500: 0.5,\n 600: 0.571,\n 700: 0.762,\n 800: 0.86,\n 900: 0.964,\n};\n\n/**\n * Target lightness for a dark-theme ramp — the ramp is **inverted**: `50` is the\n * darkest tint (a surface) and `900` the lightest (text-grade), matching the\n * `[data-tempest-theme=\"dark\"]` block in `colors.css`.\n */\nconst DARK_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.238,\n 100: 0.288,\n 200: 0.362,\n 300: 0.452,\n 400: 0.544,\n 500: 0.632,\n 600: 0.712,\n 700: 0.788,\n 800: 0.862,\n 900: 0.928,\n};\n\n/**\n * Chroma multiplier per step, relative to the input color's chroma.\n *\n * Peaks around `500`–`600` and falls off at both ends: near-white and near-black\n * tints hold very little chroma before they look muddy or leave the sRGB gamut.\n */\nconst CHROMA_CURVE: Record<ScaleStep, number> = {\n 50: 0.18,\n 100: 0.34,\n 200: 0.6,\n 300: 0.82,\n 400: 0.95,\n 500: 1,\n 600: 0.98,\n 700: 0.88,\n 800: 0.74,\n 900: 0.58,\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Expand `#abc` to `#aabbcc` and normalize to a lowercase 6-digit hex. */\nfunction normalizeHex(hex: string): string {\n const raw = hex.trim().replace(/^#/, \"\");\n const expanded =\n raw.length === 3 || raw.length === 4\n ? raw\n .slice(0, 3)\n .split(\"\")\n .map((char) => char + char)\n .join(\"\")\n : raw.slice(0, 6);\n if (!/^[0-9a-fA-F]{6}$/.test(expanded)) {\n throw new Error(`Invalid hex color: \"${hex}\"`);\n }\n return `#${expanded.toLowerCase()}`;\n}\n\n/** Parse a hex color into sRGB channels in the `0`–`1` range. */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalized = normalizeHex(hex).slice(1);\n return {\n r: parseInt(normalized.slice(0, 2), 16) / 255,\n g: parseInt(normalized.slice(2, 4), 16) / 255,\n b: parseInt(normalized.slice(4, 6), 16) / 255,\n };\n}\n\n/** Serialize sRGB channels (`0`–`1`, clamped) back to a `#rrggbb` string. */\nexport function rgbToHex(r: number, g: number, b: number): string {\n const channel = (value: number): string =>\n Math.round(clamp(value, 0, 1) * 255)\n .toString(16)\n .padStart(2, \"0\");\n return `#${channel(r)}${channel(g)}${channel(b)}`;\n}\n\nfunction srgbToLinear(channel: number): number {\n return channel <= 0.04045 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);\n}\n\nfunction linearToSrgb(channel: number): number {\n return channel <= 0.0031308 ? channel * 12.92 : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;\n}\n\n/** Convert a hex color to OKLCH. */\nexport function hexToOklch(hex: string): Oklch {\n const { r, g, b } = hexToRgb(hex);\n const lr = srgbToLinear(r);\n const lg = srgbToLinear(g);\n const lb = srgbToLinear(b);\n\n const long = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n const medium = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n const short = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n\n const l = 0.2104542553 * long + 0.793617785 * medium - 0.0040720468 * short;\n const a = 1.9779984951 * long - 2.428592205 * medium + 0.4505937099 * short;\n const bAxis = 0.0259040371 * long + 0.7827717662 * medium - 0.808675766 * short;\n\n const c = Math.sqrt(a * a + bAxis * bAxis);\n const hue = c < 1e-6 ? 0 : (Math.atan2(bAxis, a) * 180) / Math.PI;\n\n return { l, c, h: hue < 0 ? hue + 360 : hue };\n}\n\n/** Convert OKLCH to linear-light sRGB, without gamut clamping. */\nfunction oklchToLinearRgb({ l, c, h }: Oklch): { r: number; g: number; b: number } {\n const hRad = (h * Math.PI) / 180;\n const a = Math.cos(hRad) * c;\n const bAxis = Math.sin(hRad) * c;\n\n const long = (l + 0.3963377774 * a + 0.2158037573 * bAxis) ** 3;\n const medium = (l - 0.1055613458 * a - 0.0638541728 * bAxis) ** 3;\n const short = (l - 0.0894841775 * a - 1.291485548 * bAxis) ** 3;\n\n return {\n r: 4.0767416621 * long - 3.3077115913 * medium + 0.2309699292 * short,\n g: -1.2684380046 * long + 2.6097574011 * medium - 0.3413193965 * short,\n b: -0.0041960863 * long - 0.7034186147 * medium + 1.707614701 * short,\n };\n}\n\nfunction inGamut({ r, g, b }: { r: number; g: number; b: number }): boolean {\n const epsilon = 1e-4;\n return (\n r >= -epsilon &&\n r <= 1 + epsilon &&\n g >= -epsilon &&\n g <= 1 + epsilon &&\n b >= -epsilon &&\n b <= 1 + epsilon\n );\n}\n\n/**\n * Convert OKLCH to a hex color, reducing chroma until the result fits sRGB.\n *\n * Lightness and hue are preserved: desaturating is far less noticeable than\n * shifting either of them, and a naive channel clamp would do both.\n */\nexport function oklchToHex(color: Oklch): string {\n let chroma = Math.max(0, color.c);\n let rgb = oklchToLinearRgb({ ...color, c: chroma });\n\n for (let i = 0; i < 24 && !inGamut(rgb); i += 1) {\n chroma *= 0.9;\n rgb = oklchToLinearRgb({ ...color, c: chroma });\n }\n\n return rgbToHex(linearToSrgb(rgb.r), linearToSrgb(rgb.g), linearToSrgb(rgb.b));\n}\n\n/** Options for {@link createColorScale}. */\nexport interface ColorScaleOptions {\n /**\n * Pin step `500` to the input color's exact lightness. Default `true`.\n *\n * Right for a **brand** color: the hex a designer hands over is the one the\n * buttons must be. Wrong for a **neutral**: nobody checks that `gray-500` is\n * exactly the input, while everybody notices that a surface stopped being\n * near-white — anchoring rescales both halves around the input and compresses\n * exactly the range a neutral needs wide. With `false`, the ramp keeps the\n * tuned lightness curve and the input only contributes hue and chroma (a warm\n * or cool neutral, as asked).\n */\n anchor?: boolean;\n /**\n * Use the neutral lightness curve instead of the brand one. Default `false`.\n *\n * The neutral curve is wider at both ends, which is what keeps\n * `text-muted`-on-`surface-3` above AA. Implies the ramp is meant for\n * surfaces, borders and text rather than for an action color.\n */\n neutral?: boolean;\n}\n\n/**\n * Build a ten-step tint scale from a single color.\n *\n * The input color's hue is kept throughout and its chroma sets the intensity of\n * the whole ramp, so a muted brand color yields a muted scale instead of being\n * \"corrected\" into something the brand never approved.\n *\n * @param hex - Any hex color (`#abc` or `#aabbcc`), the intended `500` step.\n * @param mode - `\"light\"` for a light→dark ramp, `\"dark\"` for the inverted ramp\n * used under `[data-tempest-theme=\"dark\"]`.\n * @param options - See {@link ColorScaleOptions}.\n */\nexport function createColorScale(\n hex: string,\n mode: \"light\" | \"dark\" = \"light\",\n options: ColorScaleOptions = {},\n): ColorScale {\n const base = hexToOklch(hex);\n const targets = options.neutral\n ? mode === \"dark\"\n ? NEUTRAL_DARK_LIGHTNESS\n : NEUTRAL_LIGHT_LIGHTNESS\n : mode === \"dark\"\n ? DARK_LIGHTNESS\n : LIGHT_LIGHTNESS;\n const lightness =\n options.anchor === false ? targets : anchorLightnessAt500(targets, base.l, mode);\n const scale = {} as ColorScale;\n\n for (const step of SCALE_STEPS) {\n scale[step] = oklchToHex({\n l: lightness[step],\n c: base.c * CHROMA_CURVE[step],\n h: base.h,\n });\n }\n\n return scale;\n}\n\n/** Widest lightness band a generated ramp may span, so both ends stay usable. */\nconst LIGHTNESS_CEILING = 0.985;\nconst LIGHTNESS_FLOOR = 0.12;\n\n/**\n * Re-anchor a lightness ramp so step `500` lands on the brand color exactly.\n *\n * Without this, `500` is forced onto the ramp's own target lightness: a brand\n * `#7c3aed` came back as `#9161fe` — same hue, same chroma, *re-lightened*. It\n * looks fine in isolation and is wrong anyway, because the one color a designer\n * hands over is the one the buttons must actually be.\n *\n * Each half of the ramp is scaled independently around the anchor, so the shape\n * of the original curve survives and the ramp stays monotonic even for a very\n * light brand (yellow) or a very dark one (navy) — those simply get a shorter\n * run on the crowded side.\n *\n * @param targets - The default per-step lightness for this scheme.\n * @param anchor - Lightness of the brand color, used verbatim at step `500`.\n * @param mode - `\"dark\"` inverts which side of the ramp is the light one.\n */\nfunction anchorLightnessAt500(\n targets: Record<ScaleStep, number>,\n anchor: number,\n mode: \"light\" | \"dark\",\n): Record<ScaleStep, number> {\n const anchored = {} as Record<ScaleStep, number>;\n const base = targets[500];\n const lightEnd = mode === \"dark\" ? targets[900] : targets[50];\n const darkEnd = mode === \"dark\" ? targets[50] : targets[900];\n\n const top = Math.min(LIGHTNESS_CEILING, Math.max(lightEnd, anchor + 0.05));\n const bottom = Math.max(LIGHTNESS_FLOOR, Math.min(darkEnd, anchor - 0.05));\n\n for (const step of SCALE_STEPS) {\n const target = targets[step];\n if (target === base) {\n anchored[step] = anchor;\n } else if (target > base) {\n const ratio = (target - base) / (lightEnd - base);\n anchored[step] = anchor + ratio * (top - anchor);\n } else {\n const ratio = (base - target) / (base - darkEnd);\n anchored[step] = anchor - ratio * (anchor - bottom);\n }\n }\n\n return anchored;\n}\n\n/** WCAG 2.x relative luminance of a hex color. */\nexport function relativeLuminance(hex: string): number {\n const { r, g, b } = hexToRgb(hex);\n return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);\n}\n\n/** WCAG 2.x contrast ratio between two hex colors, from `1` to `21`. */\nexport function contrastRatio(a: string, b: string): number {\n const la = relativeLuminance(a);\n const lb = relativeLuminance(b);\n const lighter = Math.max(la, lb);\n const darker = Math.min(la, lb);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/**\n * Pick the readable foreground for a background, by contrast ratio.\n *\n * Used for `--tempest-primary-foreground`: a generated brand color can land\n * anywhere on the lightness axis, and hardcoding white would silently produce\n * unreadable buttons for light brands (yellow, lime, cyan).\n */\nexport function readableForeground(\n background: string,\n light = \"#ffffff\",\n dark = \"#101828\",\n): string {\n return contrastRatio(background, light) >= contrastRatio(background, dark) ? light : dark;\n}\n\n/** Format a hex color as `rgb(r g b / alpha)`, for focus rings and overlays. */\nexport function hexToRgbaString(hex: string, alpha: number): string {\n const { r, g, b } = hexToRgb(hex);\n const channel = (value: number): number => Math.round(clamp(value, 0, 1) * 255);\n return `rgb(${channel(r)} ${channel(g)} ${channel(b)} / ${clamp(alpha, 0, 1)})`;\n}\n"],"mappings":"AAkCA,IAAMA,EAA2B,CAAC,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAG,EAS3EC,EAA6C,CAC/C,GAAI,KACJ,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,IACL,IAAK,KACL,IAAK,KACL,IAAK,IACT,EAYMC,EAAqD,CACvD,GAAI,KACJ,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,IACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,GACT,EAMMC,EAAoD,CACtD,GAAI,KACJ,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,GACL,IAAK,KACL,IAAK,KACL,IAAK,IACL,IAAK,IACT,EAOMC,EAA4C,CAC9C,GAAI,KACJ,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,IACT,EAQMC,EAA0C,CAC5C,GAAI,IACJ,IAAK,IACL,IAAK,GACL,IAAK,IACL,IAAK,IACL,IAAK,EACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,GACT,EAEA,SAASC,EAAM,EAAe,EAAa,EAAqB,CAC5D,OAAO,KAAK,IAAIC,EAAK,KAAK,IAAIC,EAAKC,CAAK,CAAC,CAC7C,CAGA,SAASC,EAAa,EAAqB,CACvC,IAAMC,EAAMC,EAAI,KAAK,CAAC,CAAC,QAAQ,KAAM,EAAE,EACjCC,EACFF,EAAI,SAAW,GAAKA,EAAI,SAAW,EAC7BA,EACK,MAAM,EAAG,CAAC,CAAC,CACX,MAAM,EAAE,CAAC,CACT,IAAK,GAASG,EAAOA,CAAI,CAAC,CAC1B,KAAK,EAAE,EACZH,EAAI,MAAM,EAAG,CAAC,EACxB,GAAI,CAAC,mBAAmB,KAAKE,CAAQ,EACjC,MAAU,MAAM,uBAAuBD,EAAI,EAAE,EAEjD,MAAO,IAAIC,EAAS,YAAY,GACpC,CAGA,SAAgBE,EAAS,EAAkD,CACvE,IAAMC,EAAaN,EAAaE,CAAG,CAAC,CAAC,MAAM,CAAC,EAC5C,MAAO,CACH,EAAG,SAASI,EAAW,MAAM,EAAG,CAAC,EAAG,EAAE,EAAI,IAC1C,EAAG,SAASA,EAAW,MAAM,EAAG,CAAC,EAAG,EAAE,EAAI,IAC1C,EAAG,SAASA,EAAW,MAAM,EAAG,CAAC,EAAG,EAAE,EAAI,GAC9C,CACJ,CAGA,SAAgBC,EAAS,EAAW,EAAW,EAAmB,CAC9D,IAAMC,EAAW,GACb,KAAK,MAAMZ,EAAMG,EAAO,EAAG,CAAC,EAAI,GAAG,CAAC,CAC/B,SAAS,EAAE,CAAC,CACZ,SAAS,EAAG,GAAG,EACxB,MAAO,IAAIS,EAAQC,CAAC,IAAID,EAAQE,CAAC,IAAIF,EAAQG,CAAC,GAClD,CAEA,SAASC,EAAa,EAAyB,CAC3C,OAAOJ,GAAW,OAAUA,EAAU,QAAkBA,EAAU,MAAS,QAAO,GACtF,CAEA,SAASK,EAAa,EAAyB,CAC3C,OAAOL,GAAW,SAAYA,EAAU,MAAQ,MAAiBA,IAAS,EAAI,KAAO,IACzF,CAGA,SAAgBM,EAAW,EAAoB,CAC3C,GAAM,CAAE,IAAG,IAAG,KAAMT,EAASH,CAAG,EAC1Ba,EAAKH,EAAaH,CAAC,EACnBO,EAAKJ,EAAaF,CAAC,EACnBO,EAAKL,EAAaD,CAAC,EAEnBO,EAAO,KAAK,KAAK,YAAeH,EAAK,YAAeC,EAAK,YAAeC,CAAE,EAC1EE,EAAS,KAAK,KAAK,YAAeJ,EAAK,YAAeC,EAAK,YAAeC,CAAE,EAC5EG,EAAQ,KAAK,KAAK,YAAeL,EAAK,YAAeC,EAAK,YAAeC,CAAE,EAE3EI,EAAI,YAAeH,EAAO,WAAcC,EAAS,YAAeC,EAChEE,EAAI,aAAeJ,EAAO,YAAcC,EAAS,YAAeC,EAChEG,EAAQ,YAAeL,EAAO,YAAeC,EAAS,WAAcC,EAEpEI,EAAI,KAAK,KAAKF,EAAIA,EAAIC,EAAQA,CAAK,EACnCE,EAAMD,EAAI,KAAO,EAAK,KAAK,MAAMD,EAAOD,CAAC,EAAI,IAAO,KAAK,GAE/D,MAAO,CAAE,IAAG,IAAG,EAAGG,EAAM,EAAIA,EAAM,IAAMA,CAAI,CAChD,CAGA,SAASC,EAAiB,CAAE,IAAG,IAAG,KAAiD,CAC/E,IAAMC,EAAQC,EAAI,KAAK,GAAM,IACvBN,EAAI,KAAK,IAAIK,CAAI,EAAIH,EACrBD,EAAQ,KAAK,IAAII,CAAI,EAAIH,EAEzBN,GAAQG,EAAI,YAAeC,EAAI,YAAeC,IAAU,EACxDJ,GAAUE,EAAI,YAAeC,EAAI,YAAeC,IAAU,EAC1DH,GAASC,EAAI,YAAeC,EAAI,YAAcC,IAAU,EAE9D,MAAO,CACH,EAAG,aAAeL,EAAO,aAAeC,EAAS,YAAeC,EAChE,EAAG,cAAgBF,EAAO,aAAeC,EAAS,YAAeC,EACjE,EAAG,aAAgBF,EAAO,YAAeC,EAAS,YAAcC,CACpE,CACJ,CAEA,SAASS,EAAQ,CAAE,IAAG,IAAG,KAAmD,CAExE,OACIpB,GAAK,OACLA,GAAK,QACLC,GAAK,OACLA,GAAK,QACLC,GAAK,OACLA,GAAK,MAEb,CAQA,SAAgBmB,EAAW,EAAsB,CAC7C,IAAIC,EAAS,KAAK,IAAI,EAAGC,EAAM,CAAC,EAC5BC,EAAMP,EAAiB,CAAE,GAAGM,EAAO,EAAGD,CAAO,CAAC,EAElD,IAAK,IAAIG,EAAI,EAAGA,EAAI,IAAM,CAACL,EAAQI,CAAG,EAAG,GAAK,EAC1C,GAAU,GACV,EAAMP,EAAiB,CAAE,GAAGM,EAAO,EAAGD,CAAO,CAAC,EAGlD,OAAOxB,EAASM,EAAaoB,EAAI,CAAC,EAAGpB,EAAaoB,EAAI,CAAC,EAAGpB,EAAaoB,EAAI,CAAC,CAAC,CACjF,CAsCA,SAAgBE,EACZ,EACA,EAAyB,QACzB,EAA6B,CAAC,EACpB,CACV,IAAMC,EAAOtB,EAAWZ,CAAG,EACrBmC,EAAUC,EAAQ,QAClBC,IAAS,OACL9C,EACAD,EACJ+C,IAAS,OACP7C,EACAH,EACFiD,EACFF,EAAQ,SAAW,GAAQD,EAAUI,EAAqBJ,EAASD,EAAK,EAAGG,CAAI,EAC7EG,EAAQ,CAAC,EAEf,IAAK,IAAMC,KAAQrD,EACf,EAAMqD,GAAQb,EAAW,CACrB,EAAGU,EAAUG,GACb,EAAGP,EAAK,EAAIzC,EAAagD,GACzB,EAAGP,EAAK,CACZ,CAAC,EAGL,OAAOM,CACX,CAGA,IAAME,EAAoB,KACpBC,EAAkB,IAmBxB,SAASJ,EACL,EACA,EACA,EACyB,CACzB,IAAMK,EAAW,CAAC,EACZV,EAAOC,EAAQ,KACfU,EAAWR,IAAS,OAASF,EAAQ,KAAOA,EAAQ,IACpDW,EAAUT,IAAS,OAASF,EAAQ,IAAMA,EAAQ,KAElDY,EAAM,KAAK,IAAIL,EAAmB,KAAK,IAAIG,EAAUG,EAAS,GAAI,CAAC,EACnEC,EAAS,KAAK,IAAIN,EAAiB,KAAK,IAAIG,EAASE,EAAS,GAAI,CAAC,EAEzE,IAAK,IAAMP,KAAQrD,EAAa,CAC5B,IAAM8D,EAASf,EAAQM,GACvB,AAOIG,EAASH,GAPTS,IAAWhB,EACMc,EACVE,EAAShB,EAECc,GADFE,EAAShB,IAASW,EAAWX,IACTa,EAAMC,GAGxBA,GADFd,EAAOgB,IAAWhB,EAAOY,IACLE,EAASC,EAEpD,CAEA,OAAOL,CACX,CAGA,SAAgBO,EAAkB,EAAqB,CACnD,GAAM,CAAE,IAAG,IAAG,KAAMhD,EAASH,CAAG,EAChC,MAAO,OAASU,EAAaH,CAAC,EAAI,MAASG,EAAaF,CAAC,EAAI,MAASE,EAAaD,CAAC,CACxF,CAGA,SAAgB2C,EAAc,EAAW,EAAmB,CACxD,IAAMC,EAAKF,EAAkB/B,CAAC,EACxBL,EAAKoC,EAAkB1C,CAAC,EACxB6C,EAAU,KAAK,IAAID,EAAItC,CAAE,EACzBwC,EAAS,KAAK,IAAIF,EAAItC,CAAE,EAC9B,OAAQuC,EAAU,MAASC,EAAS,IACxC,CASA,SAAgBC,EACZ,EACA,EAAQ,UACR,EAAO,UACD,CACN,OAAOJ,EAAcK,EAAYC,CAAK,GAAKN,EAAcK,EAAYE,CAAI,EAAID,EAAQC,CACzF,CAGA,SAAgBC,EAAgB,EAAa,EAAuB,CAChE,GAAM,CAAE,IAAG,IAAG,KAAMzD,EAASH,CAAG,EAC1BM,EAAW,GAA0B,KAAK,MAAMZ,EAAMG,EAAO,EAAG,CAAC,EAAI,GAAG,EAC9E,MAAO,OAAOS,EAAQC,CAAC,EAAE,GAAGD,EAAQE,CAAC,EAAE,GAAGF,EAAQG,CAAC,EAAE,KAAKf,EAAMmE,EAAO,EAAG,CAAC,EAAE,EACjF,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"color.js","names":[],"sources":["../../src/theme/color.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — OKLCH ↔ sRGB with the gamut mapping in between: the\n * transfer function, the LMS matrices, the chroma search that finds the nearest in-\n * gamut colour and the contrast ratio used to check it. Matrices split across files\n * are matrices that get edited one half at a time.\n */\n/**\n * Color math behind {@link createTheme} — OKLab/OKLCH conversions, tint scale\n * generation and WCAG contrast picking.\n *\n * Everything here is pure and dependency-free: the SDK generates brand ramps at\n * runtime in the browser, so a color library would be a disproportionate cost\n * for ~150 lines of well-specified math. OKLCH is used instead of HSL because\n * HSL lightness is not perceptual — an HSL ramp of a yellow and of a blue at the\n * same `L` read as wildly different brightness, which is exactly what breaks a\n * generated palette.\n */\n\n/** A color in the OKLCH space: perceptual lightness, chroma and hue. */\nexport interface Oklch {\n /** Perceptual lightness, `0` (black) to `1` (white). */\n l: number;\n /** Chroma (colorfulness). `0` is gray; sRGB rarely exceeds `~0.37`. */\n c: number;\n /** Hue angle in degrees, `0`–`360`. */\n h: number;\n}\n\n/** The ten steps of a Tempest tint scale, lightest to darkest. */\nexport type ScaleStep = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;\n\n/** A generated tint scale, keyed by step. */\nexport type ColorScale = Record<ScaleStep, string>;\n\nconst SCALE_STEPS: ScaleStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\n\n/**\n * Target lightness per step for a **brand** ramp in light mode.\n *\n * These are the measured OKLCH lightnesses of the hand-written `--tempest-primary-*`\n * scale in `colors.css`, so a generated brand ramp lands in the same visual range\n * as the built-in one instead of merely near it.\n */\nconst LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.966,\n 100: 0.923,\n 200: 0.844,\n 300: 0.743,\n 400: 0.642,\n 500: 0.563,\n 600: 0.48,\n 700: 0.391,\n 800: 0.325,\n 900: 0.251,\n};\n\n/**\n * Target lightness per step for a **neutral** ramp in light mode — measured from\n * the hand-written `--tempest-gray-*` scale.\n *\n * Deliberately **wider** than the brand curve at both ends (`0.982` → `0.210` vs\n * `0.966` → `0.251`): a neutral carries surfaces that must read as near-white and\n * text that must read as near-black, and the pair `text-muted` on `surface-3` has\n * to clear AA. Reusing the brand curve for neutrals is what dropped that pair to\n * 3.5:1 and made the browser axe sweep fail on every generated theme.\n */\nconst NEUTRAL_LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.982,\n 100: 0.963,\n 200: 0.927,\n 300: 0.872,\n 400: 0.71,\n 500: 0.544,\n 600: 0.442,\n 700: 0.369,\n 800: 0.278,\n 900: 0.21,\n};\n\n/**\n * Neutral ramp for dark mode, measured from the `[data-tempest-theme=\"dark\"]`\n * surface/text tokens: `50` is the page background and `900` is text-grade.\n */\nconst NEUTRAL_DARK_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.159,\n 100: 0.205,\n 200: 0.254,\n 300: 0.314,\n 400: 0.381,\n 500: 0.5,\n 600: 0.571,\n 700: 0.762,\n 800: 0.86,\n 900: 0.964,\n};\n\n/**\n * Target lightness for a dark-theme ramp — the ramp is **inverted**: `50` is the\n * darkest tint (a surface) and `900` the lightest (text-grade), matching the\n * `[data-tempest-theme=\"dark\"]` block in `colors.css`.\n */\nconst DARK_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.238,\n 100: 0.288,\n 200: 0.362,\n 300: 0.452,\n 400: 0.544,\n 500: 0.632,\n 600: 0.712,\n 700: 0.788,\n 800: 0.862,\n 900: 0.928,\n};\n\n/**\n * Chroma multiplier per step, relative to the input color's chroma.\n *\n * Peaks around `500`–`600` and falls off at both ends: near-white and near-black\n * tints hold very little chroma before they look muddy or leave the sRGB gamut.\n */\nconst CHROMA_CURVE: Record<ScaleStep, number> = {\n 50: 0.18,\n 100: 0.34,\n 200: 0.6,\n 300: 0.82,\n 400: 0.95,\n 500: 1,\n 600: 0.98,\n 700: 0.88,\n 800: 0.74,\n 900: 0.58,\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Expand `#abc` to `#aabbcc` and normalize to a lowercase 6-digit hex. */\nfunction normalizeHex(hex: string): string {\n const raw = hex.trim().replace(/^#/, \"\");\n const expanded =\n raw.length === 3 || raw.length === 4\n ? raw\n .slice(0, 3)\n .split(\"\")\n .map((char) => char + char)\n .join(\"\")\n : raw.slice(0, 6);\n if (!/^[0-9a-fA-F]{6}$/.test(expanded)) {\n throw new Error(`Invalid hex color: \"${hex}\"`);\n }\n return `#${expanded.toLowerCase()}`;\n}\n\n/** Parse a hex color into sRGB channels in the `0`–`1` range. */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalized = normalizeHex(hex).slice(1);\n return {\n r: parseInt(normalized.slice(0, 2), 16) / 255,\n g: parseInt(normalized.slice(2, 4), 16) / 255,\n b: parseInt(normalized.slice(4, 6), 16) / 255,\n };\n}\n\n/** Serialize sRGB channels (`0`–`1`, clamped) back to a `#rrggbb` string. */\nexport function rgbToHex(r: number, g: number, b: number): string {\n const channel = (value: number): string =>\n Math.round(clamp(value, 0, 1) * 255)\n .toString(16)\n .padStart(2, \"0\");\n return `#${channel(r)}${channel(g)}${channel(b)}`;\n}\n\nfunction srgbToLinear(channel: number): number {\n return channel <= 0.04045 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);\n}\n\nfunction linearToSrgb(channel: number): number {\n return channel <= 0.0031308 ? channel * 12.92 : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;\n}\n\n/** Convert a hex color to OKLCH. */\nexport function hexToOklch(hex: string): Oklch {\n const { r, g, b } = hexToRgb(hex);\n const lr = srgbToLinear(r);\n const lg = srgbToLinear(g);\n const lb = srgbToLinear(b);\n\n const long = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n const medium = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n const short = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n\n const l = 0.2104542553 * long + 0.793617785 * medium - 0.0040720468 * short;\n const a = 1.9779984951 * long - 2.428592205 * medium + 0.4505937099 * short;\n const bAxis = 0.0259040371 * long + 0.7827717662 * medium - 0.808675766 * short;\n\n const c = Math.sqrt(a * a + bAxis * bAxis);\n const hue = c < 1e-6 ? 0 : (Math.atan2(bAxis, a) * 180) / Math.PI;\n\n return { l, c, h: hue < 0 ? hue + 360 : hue };\n}\n\n/** Convert OKLCH to linear-light sRGB, without gamut clamping. */\nfunction oklchToLinearRgb({ l, c, h }: Oklch): { r: number; g: number; b: number } {\n const hRad = (h * Math.PI) / 180;\n const a = Math.cos(hRad) * c;\n const bAxis = Math.sin(hRad) * c;\n\n const long = (l + 0.3963377774 * a + 0.2158037573 * bAxis) ** 3;\n const medium = (l - 0.1055613458 * a - 0.0638541728 * bAxis) ** 3;\n const short = (l - 0.0894841775 * a - 1.291485548 * bAxis) ** 3;\n\n return {\n r: 4.0767416621 * long - 3.3077115913 * medium + 0.2309699292 * short,\n g: -1.2684380046 * long + 2.6097574011 * medium - 0.3413193965 * short,\n b: -0.0041960863 * long - 0.7034186147 * medium + 1.707614701 * short,\n };\n}\n\nfunction inGamut({ r, g, b }: { r: number; g: number; b: number }): boolean {\n const epsilon = 1e-4;\n return (\n r >= -epsilon &&\n r <= 1 + epsilon &&\n g >= -epsilon &&\n g <= 1 + epsilon &&\n b >= -epsilon &&\n b <= 1 + epsilon\n );\n}\n\n/**\n * Convert OKLCH to a hex color, reducing chroma until the result fits sRGB.\n *\n * Lightness and hue are preserved: desaturating is far less noticeable than\n * shifting either of them, and a naive channel clamp would do both.\n */\nexport function oklchToHex(color: Oklch): string {\n let chroma = Math.max(0, color.c);\n let rgb = oklchToLinearRgb({ ...color, c: chroma });\n\n for (let i = 0; i < 24 && !inGamut(rgb); i += 1) {\n chroma *= 0.9;\n rgb = oklchToLinearRgb({ ...color, c: chroma });\n }\n\n return rgbToHex(linearToSrgb(rgb.r), linearToSrgb(rgb.g), linearToSrgb(rgb.b));\n}\n\n/** Options for {@link createColorScale}. */\nexport interface ColorScaleOptions {\n /**\n * Pin step `500` to the input color's exact lightness. Default `true`.\n *\n * Right for a **brand** color: the hex a designer hands over is the one the\n * buttons must be. Wrong for a **neutral**: nobody checks that `gray-500` is\n * exactly the input, while everybody notices that a surface stopped being\n * near-white — anchoring rescales both halves around the input and compresses\n * exactly the range a neutral needs wide. With `false`, the ramp keeps the\n * tuned lightness curve and the input only contributes hue and chroma (a warm\n * or cool neutral, as asked).\n */\n anchor?: boolean;\n /**\n * Use the neutral lightness curve instead of the brand one. Default `false`.\n *\n * The neutral curve is wider at both ends, which is what keeps\n * `text-muted`-on-`surface-3` above AA. Implies the ramp is meant for\n * surfaces, borders and text rather than for an action color.\n */\n neutral?: boolean;\n}\n\n/**\n * Build a ten-step tint scale from a single color.\n *\n * The input color's hue is kept throughout and its chroma sets the intensity of\n * the whole ramp, so a muted brand color yields a muted scale instead of being\n * \"corrected\" into something the brand never approved.\n *\n * @param hex - Any hex color (`#abc` or `#aabbcc`), the intended `500` step.\n * @param mode - `\"light\"` for a light→dark ramp, `\"dark\"` for the inverted ramp\n * used under `[data-tempest-theme=\"dark\"]`.\n * @param options - See {@link ColorScaleOptions}.\n */\nexport function createColorScale(\n hex: string,\n mode: \"light\" | \"dark\" = \"light\",\n options: ColorScaleOptions = {},\n): ColorScale {\n const base = hexToOklch(hex);\n const targets = options.neutral\n ? mode === \"dark\"\n ? NEUTRAL_DARK_LIGHTNESS\n : NEUTRAL_LIGHT_LIGHTNESS\n : mode === \"dark\"\n ? DARK_LIGHTNESS\n : LIGHT_LIGHTNESS;\n const lightness =\n options.anchor === false ? targets : anchorLightnessAt500(targets, base.l, mode);\n const scale = {} as ColorScale;\n\n for (const step of SCALE_STEPS) {\n scale[step] = oklchToHex({\n l: lightness[step],\n c: base.c * CHROMA_CURVE[step],\n h: base.h,\n });\n }\n\n return scale;\n}\n\n/** Widest lightness band a generated ramp may span, so both ends stay usable. */\nconst LIGHTNESS_CEILING = 0.985;\nconst LIGHTNESS_FLOOR = 0.12;\n\n/**\n * Re-anchor a lightness ramp so step `500` lands on the brand color exactly.\n *\n * Without this, `500` is forced onto the ramp's own target lightness: a brand\n * `#7c3aed` came back as `#9161fe` — same hue, same chroma, *re-lightened*. It\n * looks fine in isolation and is wrong anyway, because the one color a designer\n * hands over is the one the buttons must actually be.\n *\n * Each half of the ramp is scaled independently around the anchor, so the shape\n * of the original curve survives and the ramp stays monotonic even for a very\n * light brand (yellow) or a very dark one (navy) — those simply get a shorter\n * run on the crowded side.\n *\n * @param targets - The default per-step lightness for this scheme.\n * @param anchor - Lightness of the brand color, used verbatim at step `500`.\n * @param mode - `\"dark\"` inverts which side of the ramp is the light one.\n */\nfunction anchorLightnessAt500(\n targets: Record<ScaleStep, number>,\n anchor: number,\n mode: \"light\" | \"dark\",\n): Record<ScaleStep, number> {\n const anchored = {} as Record<ScaleStep, number>;\n const base = targets[500];\n const lightEnd = mode === \"dark\" ? targets[900] : targets[50];\n const darkEnd = mode === \"dark\" ? targets[50] : targets[900];\n\n const top = Math.min(LIGHTNESS_CEILING, Math.max(lightEnd, anchor + 0.05));\n const bottom = Math.max(LIGHTNESS_FLOOR, Math.min(darkEnd, anchor - 0.05));\n\n for (const step of SCALE_STEPS) {\n const target = targets[step];\n if (target === base) {\n anchored[step] = anchor;\n } else if (target > base) {\n const ratio = (target - base) / (lightEnd - base);\n anchored[step] = anchor + ratio * (top - anchor);\n } else {\n const ratio = (base - target) / (base - darkEnd);\n anchored[step] = anchor - ratio * (anchor - bottom);\n }\n }\n\n return anchored;\n}\n\n/** WCAG 2.x relative luminance of a hex color. */\nexport function relativeLuminance(hex: string): number {\n const { r, g, b } = hexToRgb(hex);\n return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);\n}\n\n/** WCAG 2.x contrast ratio between two hex colors, from `1` to `21`. */\nexport function contrastRatio(a: string, b: string): number {\n const la = relativeLuminance(a);\n const lb = relativeLuminance(b);\n const lighter = Math.max(la, lb);\n const darker = Math.min(la, lb);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/**\n * Pick the readable foreground for a background, by contrast ratio.\n *\n * Used for `--tempest-primary-foreground`: a generated brand color can land\n * anywhere on the lightness axis, and hardcoding white would silently produce\n * unreadable buttons for light brands (yellow, lime, cyan).\n */\nexport function readableForeground(\n background: string,\n light = \"#ffffff\",\n dark = \"#101828\",\n): string {\n return contrastRatio(background, light) >= contrastRatio(background, dark) ? light : dark;\n}\n\n/** Format a hex color as `rgb(r g b / alpha)`, for focus rings and overlays. */\nexport function hexToRgbaString(hex: string, alpha: number): string {\n const { r, g, b } = hexToRgb(hex);\n const channel = (value: number): number => Math.round(clamp(value, 0, 1) * 255);\n return `rgb(${channel(r)} ${channel(g)} ${channel(b)} / ${clamp(alpha, 0, 1)})`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"color.js","names":["SCALE_STEPS","LIGHT_LIGHTNESS","NEUTRAL_LIGHT_LIGHTNESS","NEUTRAL_DARK_LIGHTNESS","DARK_LIGHTNESS","CHROMA_CURVE","clamp","max","min","value","normalizeHex","raw","hex","expanded","char","hexToRgb","normalized","rgbToHex","channel","r","g","b","srgbToLinear","linearToSrgb","hexToOklch","lr","lg","lb","long","medium","short","l","a","bAxis","c","hue","oklchToLinearRgb","hRad","h","inGamut","oklchToHex","chroma","color","rgb","i","createColorScale","base","targets","options","mode","lightness","anchorLightnessAt500","scale","step","LIGHTNESS_CEILING","LIGHTNESS_FLOOR","anchored","lightEnd","darkEnd","top","anchor","bottom","target","relativeLuminance","contrastRatio","la","lighter","darker","readableForeground","background","light","dark","hexToRgbaString","alpha"],"sources":["../../src/theme/color.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — OKLCH ↔ sRGB with the gamut mapping in between: the\n * transfer function, the LMS matrices, the chroma search that finds the nearest in-\n * gamut colour and the contrast ratio used to check it. Matrices split across files\n * are matrices that get edited one half at a time.\n */\n/**\n * Color math behind {@link createTheme} — OKLab/OKLCH conversions, tint scale\n * generation and WCAG contrast picking.\n *\n * Everything here is pure and dependency-free: the SDK generates brand ramps at\n * runtime in the browser, so a color library would be a disproportionate cost\n * for ~150 lines of well-specified math. OKLCH is used instead of HSL because\n * HSL lightness is not perceptual — an HSL ramp of a yellow and of a blue at the\n * same `L` read as wildly different brightness, which is exactly what breaks a\n * generated palette.\n */\n\n/** A color in the OKLCH space: perceptual lightness, chroma and hue. */\nexport interface Oklch {\n /** Perceptual lightness, `0` (black) to `1` (white). */\n l: number;\n /** Chroma (colorfulness). `0` is gray; sRGB rarely exceeds `~0.37`. */\n c: number;\n /** Hue angle in degrees, `0`–`360`. */\n h: number;\n}\n\n/** The ten steps of a Tempest tint scale, lightest to darkest. */\nexport type ScaleStep = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;\n\n/** A generated tint scale, keyed by step. */\nexport type ColorScale = Record<ScaleStep, string>;\n\nconst SCALE_STEPS: ScaleStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\n\n/**\n * Target lightness per step for a **brand** ramp in light mode.\n *\n * These are the measured OKLCH lightnesses of the hand-written `--tempest-primary-*`\n * scale in `colors.css`, so a generated brand ramp lands in the same visual range\n * as the built-in one instead of merely near it.\n */\nconst LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.966,\n 100: 0.923,\n 200: 0.844,\n 300: 0.743,\n 400: 0.642,\n 500: 0.563,\n 600: 0.48,\n 700: 0.391,\n 800: 0.325,\n 900: 0.251,\n};\n\n/**\n * Target lightness per step for a **neutral** ramp in light mode — measured from\n * the hand-written `--tempest-gray-*` scale.\n *\n * Deliberately **wider** than the brand curve at both ends (`0.982` → `0.210` vs\n * `0.966` → `0.251`): a neutral carries surfaces that must read as near-white and\n * text that must read as near-black, and the pair `text-muted` on `surface-3` has\n * to clear AA. Reusing the brand curve for neutrals is what dropped that pair to\n * 3.5:1 and made the browser axe sweep fail on every generated theme.\n */\nconst NEUTRAL_LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.982,\n 100: 0.963,\n 200: 0.927,\n 300: 0.872,\n 400: 0.71,\n 500: 0.544,\n 600: 0.442,\n 700: 0.369,\n 800: 0.278,\n 900: 0.21,\n};\n\n/**\n * Neutral ramp for dark mode, measured from the `[data-tempest-theme=\"dark\"]`\n * surface/text tokens: `50` is the page background and `900` is text-grade.\n */\nconst NEUTRAL_DARK_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.159,\n 100: 0.205,\n 200: 0.254,\n 300: 0.314,\n 400: 0.381,\n 500: 0.5,\n 600: 0.571,\n 700: 0.762,\n 800: 0.86,\n 900: 0.964,\n};\n\n/**\n * Target lightness for a dark-theme ramp — the ramp is **inverted**: `50` is the\n * darkest tint (a surface) and `900` the lightest (text-grade), matching the\n * `[data-tempest-theme=\"dark\"]` block in `colors.css`.\n */\nconst DARK_LIGHTNESS: Record<ScaleStep, number> = {\n 50: 0.238,\n 100: 0.288,\n 200: 0.362,\n 300: 0.452,\n 400: 0.544,\n 500: 0.632,\n 600: 0.712,\n 700: 0.788,\n 800: 0.862,\n 900: 0.928,\n};\n\n/**\n * Chroma multiplier per step, relative to the input color's chroma.\n *\n * Peaks around `500`–`600` and falls off at both ends: near-white and near-black\n * tints hold very little chroma before they look muddy or leave the sRGB gamut.\n */\nconst CHROMA_CURVE: Record<ScaleStep, number> = {\n 50: 0.18,\n 100: 0.34,\n 200: 0.6,\n 300: 0.82,\n 400: 0.95,\n 500: 1,\n 600: 0.98,\n 700: 0.88,\n 800: 0.74,\n 900: 0.58,\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Expand `#abc` to `#aabbcc` and normalize to a lowercase 6-digit hex. */\nfunction normalizeHex(hex: string): string {\n const raw = hex.trim().replace(/^#/, \"\");\n const expanded =\n raw.length === 3 || raw.length === 4\n ? raw\n .slice(0, 3)\n .split(\"\")\n .map((char) => char + char)\n .join(\"\")\n : raw.slice(0, 6);\n if (!/^[0-9a-fA-F]{6}$/.test(expanded)) {\n throw new Error(`Invalid hex color: \"${hex}\"`);\n }\n return `#${expanded.toLowerCase()}`;\n}\n\n/** Parse a hex color into sRGB channels in the `0`–`1` range. */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalized = normalizeHex(hex).slice(1);\n return {\n r: parseInt(normalized.slice(0, 2), 16) / 255,\n g: parseInt(normalized.slice(2, 4), 16) / 255,\n b: parseInt(normalized.slice(4, 6), 16) / 255,\n };\n}\n\n/** Serialize sRGB channels (`0`–`1`, clamped) back to a `#rrggbb` string. */\nexport function rgbToHex(r: number, g: number, b: number): string {\n const channel = (value: number): string =>\n Math.round(clamp(value, 0, 1) * 255)\n .toString(16)\n .padStart(2, \"0\");\n return `#${channel(r)}${channel(g)}${channel(b)}`;\n}\n\nfunction srgbToLinear(channel: number): number {\n return channel <= 0.04045 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);\n}\n\nfunction linearToSrgb(channel: number): number {\n return channel <= 0.0031308 ? channel * 12.92 : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;\n}\n\n/** Convert a hex color to OKLCH. */\nexport function hexToOklch(hex: string): Oklch {\n const { r, g, b } = hexToRgb(hex);\n const lr = srgbToLinear(r);\n const lg = srgbToLinear(g);\n const lb = srgbToLinear(b);\n\n const long = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n const medium = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n const short = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n\n const l = 0.2104542553 * long + 0.793617785 * medium - 0.0040720468 * short;\n const a = 1.9779984951 * long - 2.428592205 * medium + 0.4505937099 * short;\n const bAxis = 0.0259040371 * long + 0.7827717662 * medium - 0.808675766 * short;\n\n const c = Math.sqrt(a * a + bAxis * bAxis);\n const hue = c < 1e-6 ? 0 : (Math.atan2(bAxis, a) * 180) / Math.PI;\n\n return { l, c, h: hue < 0 ? hue + 360 : hue };\n}\n\n/** Convert OKLCH to linear-light sRGB, without gamut clamping. */\nfunction oklchToLinearRgb({ l, c, h }: Oklch): { r: number; g: number; b: number } {\n const hRad = (h * Math.PI) / 180;\n const a = Math.cos(hRad) * c;\n const bAxis = Math.sin(hRad) * c;\n\n const long = (l + 0.3963377774 * a + 0.2158037573 * bAxis) ** 3;\n const medium = (l - 0.1055613458 * a - 0.0638541728 * bAxis) ** 3;\n const short = (l - 0.0894841775 * a - 1.291485548 * bAxis) ** 3;\n\n return {\n r: 4.0767416621 * long - 3.3077115913 * medium + 0.2309699292 * short,\n g: -1.2684380046 * long + 2.6097574011 * medium - 0.3413193965 * short,\n b: -0.0041960863 * long - 0.7034186147 * medium + 1.707614701 * short,\n };\n}\n\nfunction inGamut({ r, g, b }: { r: number; g: number; b: number }): boolean {\n const epsilon = 1e-4;\n return (\n r >= -epsilon &&\n r <= 1 + epsilon &&\n g >= -epsilon &&\n g <= 1 + epsilon &&\n b >= -epsilon &&\n b <= 1 + epsilon\n );\n}\n\n/**\n * Convert OKLCH to a hex color, reducing chroma until the result fits sRGB.\n *\n * Lightness and hue are preserved: desaturating is far less noticeable than\n * shifting either of them, and a naive channel clamp would do both.\n */\nexport function oklchToHex(color: Oklch): string {\n let chroma = Math.max(0, color.c);\n let rgb = oklchToLinearRgb({ ...color, c: chroma });\n\n for (let i = 0; i < 24 && !inGamut(rgb); i += 1) {\n chroma *= 0.9;\n rgb = oklchToLinearRgb({ ...color, c: chroma });\n }\n\n return rgbToHex(linearToSrgb(rgb.r), linearToSrgb(rgb.g), linearToSrgb(rgb.b));\n}\n\n/** Options for {@link createColorScale}. */\nexport interface ColorScaleOptions {\n /**\n * Pin step `500` to the input color's exact lightness. Default `true`.\n *\n * Right for a **brand** color: the hex a designer hands over is the one the\n * buttons must be. Wrong for a **neutral**: nobody checks that `gray-500` is\n * exactly the input, while everybody notices that a surface stopped being\n * near-white — anchoring rescales both halves around the input and compresses\n * exactly the range a neutral needs wide. With `false`, the ramp keeps the\n * tuned lightness curve and the input only contributes hue and chroma (a warm\n * or cool neutral, as asked).\n */\n anchor?: boolean;\n /**\n * Use the neutral lightness curve instead of the brand one. Default `false`.\n *\n * The neutral curve is wider at both ends, which is what keeps\n * `text-muted`-on-`surface-3` above AA. Implies the ramp is meant for\n * surfaces, borders and text rather than for an action color.\n */\n neutral?: boolean;\n}\n\n/**\n * Build a ten-step tint scale from a single color.\n *\n * The input color's hue is kept throughout and its chroma sets the intensity of\n * the whole ramp, so a muted brand color yields a muted scale instead of being\n * \"corrected\" into something the brand never approved.\n *\n * @param hex - Any hex color (`#abc` or `#aabbcc`), the intended `500` step.\n * @param mode - `\"light\"` for a light→dark ramp, `\"dark\"` for the inverted ramp\n * used under `[data-tempest-theme=\"dark\"]`.\n * @param options - See {@link ColorScaleOptions}.\n */\nexport function createColorScale(\n hex: string,\n mode: \"light\" | \"dark\" = \"light\",\n options: ColorScaleOptions = {},\n): ColorScale {\n const base = hexToOklch(hex);\n const targets = options.neutral\n ? mode === \"dark\"\n ? NEUTRAL_DARK_LIGHTNESS\n : NEUTRAL_LIGHT_LIGHTNESS\n : mode === \"dark\"\n ? DARK_LIGHTNESS\n : LIGHT_LIGHTNESS;\n const lightness =\n options.anchor === false ? targets : anchorLightnessAt500(targets, base.l, mode);\n const scale = {} as ColorScale;\n\n for (const step of SCALE_STEPS) {\n scale[step] = oklchToHex({\n l: lightness[step],\n c: base.c * CHROMA_CURVE[step],\n h: base.h,\n });\n }\n\n return scale;\n}\n\n/** Widest lightness band a generated ramp may span, so both ends stay usable. */\nconst LIGHTNESS_CEILING = 0.985;\nconst LIGHTNESS_FLOOR = 0.12;\n\n/**\n * Re-anchor a lightness ramp so step `500` lands on the brand color exactly.\n *\n * Without this, `500` is forced onto the ramp's own target lightness: a brand\n * `#7c3aed` came back as `#9161fe` — same hue, same chroma, *re-lightened*. It\n * looks fine in isolation and is wrong anyway, because the one color a designer\n * hands over is the one the buttons must actually be.\n *\n * Each half of the ramp is scaled independently around the anchor, so the shape\n * of the original curve survives and the ramp stays monotonic even for a very\n * light brand (yellow) or a very dark one (navy) — those simply get a shorter\n * run on the crowded side.\n *\n * @param targets - The default per-step lightness for this scheme.\n * @param anchor - Lightness of the brand color, used verbatim at step `500`.\n * @param mode - `\"dark\"` inverts which side of the ramp is the light one.\n */\nfunction anchorLightnessAt500(\n targets: Record<ScaleStep, number>,\n anchor: number,\n mode: \"light\" | \"dark\",\n): Record<ScaleStep, number> {\n const anchored = {} as Record<ScaleStep, number>;\n const base = targets[500];\n const lightEnd = mode === \"dark\" ? targets[900] : targets[50];\n const darkEnd = mode === \"dark\" ? targets[50] : targets[900];\n\n const top = Math.min(LIGHTNESS_CEILING, Math.max(lightEnd, anchor + 0.05));\n const bottom = Math.max(LIGHTNESS_FLOOR, Math.min(darkEnd, anchor - 0.05));\n\n for (const step of SCALE_STEPS) {\n const target = targets[step];\n if (target === base) {\n anchored[step] = anchor;\n } else if (target > base) {\n const ratio = (target - base) / (lightEnd - base);\n anchored[step] = anchor + ratio * (top - anchor);\n } else {\n const ratio = (base - target) / (base - darkEnd);\n anchored[step] = anchor - ratio * (anchor - bottom);\n }\n }\n\n return anchored;\n}\n\n/** WCAG 2.x relative luminance of a hex color. */\nexport function relativeLuminance(hex: string): number {\n const { r, g, b } = hexToRgb(hex);\n return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);\n}\n\n/** WCAG 2.x contrast ratio between two hex colors, from `1` to `21`. */\nexport function contrastRatio(a: string, b: string): number {\n const la = relativeLuminance(a);\n const lb = relativeLuminance(b);\n const lighter = Math.max(la, lb);\n const darker = Math.min(la, lb);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/**\n * Pick the readable foreground for a background, by contrast ratio.\n *\n * Used for `--tempest-primary-foreground`: a generated brand color can land\n * anywhere on the lightness axis, and hardcoding white would silently produce\n * unreadable buttons for light brands (yellow, lime, cyan).\n */\nexport function readableForeground(\n background: string,\n light = \"#ffffff\",\n dark = \"#101828\",\n): string {\n return contrastRatio(background, light) >= contrastRatio(background, dark) ? light : dark;\n}\n\n/** Format a hex color as `rgb(r g b / alpha)`, for focus rings and overlays. */\nexport function hexToRgbaString(hex: string, alpha: number): string {\n const { r, g, b } = hexToRgb(hex);\n const channel = (value: number): number => Math.round(clamp(value, 0, 1) * 255);\n return `rgb(${channel(r)} ${channel(g)} ${channel(b)} / ${clamp(alpha, 0, 1)})`;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-theme.cjs","names":[],"sources":["../../src/theme/create-theme.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — one pass that emits the whole token set — surfaces,\n * text, borders, states, the chart ramps — for both modes, with every value checked\n * against the surface it will sit on. The checks are what make the length: each\n * token is derived and then verified against the same background table.\n */\n/**\n * Theme factory: turns a handful of brand colors into the full set of\n * `--tempest-*` token overrides, for both light and dark.\n *\n * Rebranding used to mean hand-writing ~167 custom properties (and getting the\n * dark ramp inversion right by hand). `createTheme({ primary: \"#7c3aed\" })`\n * emits the same thing, derived in OKLCH so the ramp stays perceptually even.\n */\nimport {\n contrastRatio,\n createColorScale,\n hexToRgbaString,\n readableForeground,\n type ColorScale,\n type ScaleStep,\n} from \"./color\";\nimport { buildDivergingRamp, buildRamp, hueOf } from \"./data-viz-ramps\";\nimport { isDevBuild } from \"../utils/dev-mode\";\nimport {\n INVERSE_SELECTOR,\n renderInverseSurface,\n type InverseSurfaceGenerator,\n} from \"./inverse-render\";\nimport { ON_SOLID_INK, THEME_STATUSES, writeStatus } from \"./status-tokens\";\n\n/** Radius presets, applied to the whole `--tempest-radius-*` family at once. */\nexport type ThemeRadius = \"none\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\";\n\nexport type { ThemeStatus } from \"./status-tokens\";\n\n/** Input for {@link createTheme}. Every field is optional — omitted families keep the built-in tokens. */\nexport interface CreateThemeOptions {\n /** Brand color, used as the `500` step of the primary scale. */\n primary?: string;\n /** Neutral color, used as the `500` step of the gray scale (surfaces, borders, text). */\n gray?: string;\n /** Success color (`--tempest-success*`). */\n success?: string;\n /** Warning color (`--tempest-warning*`). */\n warning?: string;\n /** Danger color (`--tempest-danger*`). */\n danger?: string;\n /** Info color (`--tempest-info*`). */\n info?: string;\n /**\n * Categorical series colors for `tempest-react-sdk/charts`, in cycle order.\n * Written to `--tempest-chart-1` … `--tempest-chart-N`, so charts follow the\n * theme instead of a hardcoded palette.\n */\n chart?: string[];\n /** Corner radius scale. A preset name, or explicit per-step values. */\n radius?: ThemeRadius | Partial<Record<\"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\", string>>;\n /**\n * Opacity of `--tempest-focus-ring-color`. Omit it — the default ring is opaque.\n *\n * A translucent ring has no contrast of its own; it has the contrast of\n * whatever it composites over. Passing a value below `1` reintroduces the\n * failure 0.61.0 fixed in the built-in tokens, and logs a warning in a\n * development build. Kept because a translucent ring over a background you\n * control is a legitimate choice.\n */\n focusRingAlpha?: number;\n /** Selector the light tokens are written under. Default `\":root\"`. */\n selector?: string;\n /** Selector the dark tokens are written under. Default `'[data-tempest-theme=\"dark\"]'`. */\n darkSelector?: string;\n /**\n * Also emit the inverse surface — the token set for a section painted in the\n * brand color — by passing its generator, `createInverseSurface`. Off by\n * default; ignored without `primary`.\n *\n * The generator is passed in rather than switched on with `true` so that\n * `createTheme` never imports it: an app that does not paint a section in\n * its brand does not ship the 1.68 kB brotli it costs.\n *\n * @example\n * ```ts\n * import { createInverseSurface, createTheme } from \"tempest-react-sdk\";\n *\n * createTheme({ primary: \"#03184b\", inverse: createInverseSurface });\n * ```\n */\n inverse?: InverseSurfaceGenerator;\n /** Selector the inverse tokens are written under. Default `'[data-tempest-tone=\"inverse\"]'`. */\n inverseSelector?: string;\n}\n\n/** A generated theme: token maps per color scheme, plus the CSS text that carries them. */\nexport interface GeneratedTheme {\n /** Light-scheme custom properties, without the leading `--`-less names (keys include `--`). */\n light: Record<string, string>;\n /** Dark-scheme custom properties. */\n dark: Record<string, string>;\n /**\n * Inverse-surface custom properties — literal colors, identical under the\n * light and the dark page scheme. Present only when the theme names a\n * `primary` and passes `inverse`.\n */\n inverse?: Record<string, string>;\n /** Both blocks rendered as CSS, ready for {@link applyTheme} or a stylesheet. */\n css: string;\n}\n\nconst RADIUS_PRESETS: Record<ThemeRadius, Record<string, string>> = {\n none: { xs: \"0\", sm: \"0\", md: \"0\", lg: \"0\", xl: \"0\", \"2xl\": \"0\" },\n sm: { xs: \"1px\", sm: \"2px\", md: \"4px\", lg: \"6px\", xl: \"8px\", \"2xl\": \"12px\" },\n md: { xs: \"2px\", sm: \"4px\", md: \"8px\", lg: \"12px\", xl: \"16px\", \"2xl\": \"24px\" },\n lg: { xs: \"4px\", sm: \"6px\", md: \"12px\", lg: \"16px\", xl: \"22px\", \"2xl\": \"32px\" },\n xl: { xs: \"6px\", sm: \"10px\", md: \"16px\", lg: \"24px\", xl: \"32px\", \"2xl\": \"44px\" },\n full: { xs: \"4px\", sm: \"8px\", md: \"9999px\", lg: \"9999px\", xl: \"9999px\", \"2xl\": \"9999px\" },\n};\n\nconst SCALE_STEPS: ScaleStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\n\nfunction writeScale(tokens: Record<string, string>, name: string, scale: ColorScale): void {\n for (const step of SCALE_STEPS) {\n tokens[`--tempest-${name}-${step}`] = scale[step];\n }\n}\n\n/** Minimum contrast for body text, WCAG 2.x AA. */\nconst AA_TEXT_CONTRAST = 4.5;\n\n/**\n * Choose the ramp step for text sitting on the soft tint.\n *\n * A fixed step does not survive an arbitrary brand color: the built-in blue only\n * reaches 4.37:1 at `500` over its own `50` tint, and a generated emerald lands\n * at 4.41:1 at `600` — both fail AA for body text by a hair. So the step is\n * picked by measuring, walking away from the tint until it clears AA, and\n * falling back to the most extreme candidate when even that cannot (a very light\n * or very desaturated brand).\n *\n * @param scale - The generated ramp.\n * @param softStep - Step used as `--tempest-primary-soft`.\n * @param candidates - Steps to try, in order of preference.\n * @returns The first candidate clearing {@link AA_TEXT_CONTRAST}, else the last.\n */\nfunction pickOnSoftStep(\n scale: ColorScale,\n softStep: ScaleStep,\n candidates: ScaleStep[],\n): ScaleStep {\n for (const step of candidates) {\n if (contrastRatio(scale[softStep], scale[step]) >= AA_TEXT_CONTRAST) return step;\n }\n return candidates[candidates.length - 1];\n}\n\n/** Minimum contrast for a non-text indicator, WCAG 2.2 SC 1.4.11. */\nconst INDICATOR_CONTRAST = 3;\n\n/**\n * The four surfaces a focus ring can land on, as the SDK's own `colors.css`\n * paints them.\n *\n * Ported from `src/styles/colors.css` (`--tempest-bg`, `--tempest-surface`,\n * `--tempest-surface-2`, `--tempest-surface-3`, resolved through the gray ramp),\n * and pinned by a test that reads that file — a theme that only names `primary`\n * keeps these, so the ring has to be measured against them and not against a\n * guess. The light values resolve through `--tempest-gray-50/100/200`; the dark\n * ones are literals in the dark block.\n */\nconst SDK_SURFACES: Record<\"light\" | \"dark\", readonly string[]> = {\n light: [\"#ffffff\", \"#f8f9fb\", \"#f1f3f6\", \"#e4e7ec\"],\n dark: [\"#0b0d12\", \"#14171f\", \"#1d2230\", \"#262d3f\"],\n};\n\n/**\n * Ramp steps to try for the focus ring, in order.\n *\n * `500` first, because the ring should read as the brand when it can, then up\n * the ramp — which moves away from the surfaces in **both** schemes, because\n * `createColorScale` inverts the dark ramp: there `50` is the darkest step (it\n * is what `--tempest-bg` is made of) and `900` the lightest. Walking down in\n * dark mode looks like the right inversion and is the wrong direction; measured,\n * it left a near-black brand's ring at 1.04:1 over its own background.\n */\nconst FOCUS_RING_CANDIDATES: readonly ScaleStep[] = [500, 600, 700, 800, 900];\n\n/**\n * Choose the ramp step for the focus ring, by measuring it against the surfaces\n * it will actually be drawn on.\n *\n * A fixed step does not survive an arbitrary brand, and the measurement says so\n * loudly: of twelve brands checked against the four surfaces in both schemes —\n * 96 pairings — `500` opaque clears 3:1 in 58 of them, and `500` at the old\n * default alpha of 0.35 in 3. Picking the step by measurement clears all 96. The\n * brand from the report that opened this\n * (`#8100D7`) passes in light at 7.20:1 and fails in **dark** at 2.70:1 down to\n * 1.91:1 on `surface-3`; a yellow fails in light at 1.43:1. So the step is\n * picked the way {@link pickOnSoftStep} picks text on a tint: walk away from the\n * surfaces until the ring clears the floor against *all* of them.\n *\n * The fallback is the candidate with the best worst case rather than the last\n * one, because \"the most extreme step\" is not always the most contrasting one\n * once a brand is near-neutral.\n *\n * @param scale - The generated ramp.\n * @param surfaces - The four surfaces this theme will paint, opaque hex.\n * @returns The first candidate clearing {@link INDICATOR_CONTRAST} on every\n * surface, else the candidate whose weakest pairing is strongest.\n */\nfunction pickFocusRingStep(scale: ColorScale, surfaces: readonly string[]): ScaleStep {\n const worstCase = (step: ScaleStep): number =>\n Math.min(...surfaces.map((surface) => contrastRatio(scale[step], surface)));\n let best: ScaleStep = FOCUS_RING_CANDIDATES[0] as ScaleStep;\n let bestRatio = -1;\n for (const step of FOCUS_RING_CANDIDATES) {\n const measured = worstCase(step);\n if (measured >= INDICATOR_CONTRAST) return step;\n if (measured > bestRatio) {\n best = step;\n bestRatio = measured;\n }\n }\n return best;\n}\n\n/**\n * The surfaces this theme will actually paint, per scheme.\n *\n * A theme that names `gray` repaints all four, so measuring the ring against the\n * SDK's would be measuring the wrong backdrop — and a theme that does not keeps\n * the SDK's, which is the common case. The order and the ramp steps mirror\n * {@link writeNeutralAliases}, which is what emits them.\n *\n * @param scheme - Which scheme is being emitted.\n * @param grayScales - The generated neutral ramps, when the theme names one.\n * @returns Four opaque hex colors: bg, surface, surface-2, surface-3.\n */\nfunction surfacesOf(\n scheme: \"light\" | \"dark\",\n grayScales: { light: ColorScale; dark: ColorScale } | undefined,\n): readonly string[] {\n if (!grayScales) return SDK_SURFACES[scheme];\n const scale = grayScales[scheme];\n return scheme === \"light\"\n ? [\"#ffffff\", scale[50], scale[100], scale[200]]\n : [scale[50], scale[100], scale[200], scale[300]];\n}\n\n/**\n * Warn, in a development build, that an alpha was asked for the focus ring.\n *\n * A translucent ring has no contrast of its own — it has the contrast of\n * whatever it composites over — and that is the failure this option used to\n * ship by default: measured at alpha `0.35`, twelve brands across four surfaces\n * and both schemes produced 96 pairings, of which 3 cleared the 3:1 of WCAG 2.2\n * SC 1.4.11. It stays available, because a translucent ring over a\n * known background is a legitimate choice, but it is a choice a theme now has to\n * make on purpose.\n *\n * The warning is the difficult part to notice otherwise: a failing focus ring is\n * visible, it just does not separate.\n *\n * @param focusRingAlpha - The opacity the caller asked for, if any.\n */\nfunction warnOnTranslucentFocusRing(focusRingAlpha: number | undefined): void {\n if (focusRingAlpha === undefined || focusRingAlpha >= 1) return;\n if (!isDevBuild()) return;\n console.warn(\n `[tempest-react-sdk] createTheme({ focusRingAlpha: ${focusRingAlpha} }) makes the focus ring ` +\n \"translucent, so its contrast becomes whatever it composites over — measured below the 3:1 \" +\n \"of WCAG 2.2 SC 1.4.11 on every surface the SDK paints. Drop the option to get the opaque \" +\n \"ring, which is derived from your brand ramp and measured against those surfaces.\",\n );\n}\n\n/**\n * Emit the primary aliases for one scheme.\n *\n * The dark scheme walks the ramp the other way (hover is *lighter*, the soft\n * tint is a dark shade, and readable text on that tint is a light shade) — the\n * same inversion the built-in `colors.css` dark block does by hand.\n *\n * The selected-state indicator is derived from the same measurement as the focus\n * ring and emitted as its own token. It never takes `focusRingAlpha`: a\n * translucent ring over a known background is a legitimate choice a theme can\n * make, while a translucent *state* indicator has the contrast of whatever it\n * composites over, which is the defect this token exists to end.\n *\n * @param tokens - The token map for this scheme, written in place.\n * @param scale - The generated primary ramp.\n * @param scheme - Which scheme is being emitted.\n * @param surfaces - The surfaces this theme paints, for the focus-ring measurement.\n * @param focusRingAlpha - Opacity asked for the ring, or `undefined` for opaque.\n */\nfunction writePrimaryAliases(\n tokens: Record<string, string>,\n scale: ColorScale,\n scheme: \"light\" | \"dark\",\n surfaces: readonly string[],\n focusRingAlpha: number | undefined,\n): void {\n tokens[\"--tempest-primary\"] = \"var(--tempest-primary-500)\";\n if (scheme === \"light\") {\n tokens[\"--tempest-primary-hover\"] = \"var(--tempest-primary-600)\";\n tokens[\"--tempest-primary-active\"] = \"var(--tempest-primary-700)\";\n tokens[\"--tempest-primary-soft\"] = \"var(--tempest-primary-50)\";\n tokens[\"--tempest-primary-soft-hover\"] = \"var(--tempest-primary-100)\";\n tokens[\"--tempest-primary-on-soft\"] =\n `var(--tempest-primary-${pickOnSoftStep(scale, 50, [600, 700, 800, 900])})`;\n } else {\n tokens[\"--tempest-primary-hover\"] = \"var(--tempest-primary-400)\";\n tokens[\"--tempest-primary-active\"] = \"var(--tempest-primary-300)\";\n tokens[\"--tempest-primary-soft\"] = \"var(--tempest-primary-100)\";\n tokens[\"--tempest-primary-soft-hover\"] = \"var(--tempest-primary-200)\";\n tokens[\"--tempest-primary-on-soft\"] =\n `var(--tempest-primary-${pickOnSoftStep(scale, 100, [700, 800, 900])})`;\n }\n\n const foreground = readableForeground(scale[500]);\n tokens[\"--tempest-primary-foreground\"] = foreground;\n tokens[\"--tempest-text-on-primary\"] = foreground;\n const ring = scale[pickFocusRingStep(scale, surfaces)];\n tokens[\"--tempest-focus-ring-color\"] =\n focusRingAlpha === undefined || focusRingAlpha >= 1\n ? ring\n : hexToRgbaString(ring, focusRingAlpha);\n tokens[\"--tempest-selected-indicator\"] = ring;\n}\n\n/**\n * Emit the neutral surface/border/text aliases from a generated gray scale.\n *\n * `--tempest-bg` is pushed past the ramp on purpose: pure white in light mode and\n * a shade darker than `gray-50` in dark mode, so a raised surface still reads as\n * raised against the page.\n */\nfunction writeNeutralAliases(\n tokens: Record<string, string>,\n scale: ColorScale,\n scheme: \"light\" | \"dark\",\n): void {\n if (scheme === \"light\") {\n tokens[\"--tempest-bg\"] = \"#ffffff\";\n tokens[\"--tempest-surface\"] = \"var(--tempest-gray-50)\";\n tokens[\"--tempest-surface-2\"] = \"var(--tempest-gray-100)\";\n tokens[\"--tempest-surface-3\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-border\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-border-strong\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-text\"] = \"var(--tempest-gray-900)\";\n tokens[\"--tempest-text-muted\"] = \"var(--tempest-gray-600)\";\n tokens[\"--tempest-text-subtle\"] = \"var(--tempest-gray-500)\";\n } else {\n tokens[\"--tempest-bg\"] = scale[50];\n tokens[\"--tempest-surface\"] = \"var(--tempest-gray-100)\";\n tokens[\"--tempest-surface-2\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-surface-3\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-border\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-border-strong\"] = \"var(--tempest-gray-400)\";\n tokens[\"--tempest-text\"] = \"var(--tempest-gray-900)\";\n tokens[\"--tempest-text-muted\"] = \"var(--tempest-gray-700)\";\n tokens[\"--tempest-text-subtle\"] = \"var(--tempest-gray-600)\";\n }\n tokens[\"--tempest-neutral-on-solid\"] = readableForeground(scale[700], \"#ffffff\", ON_SOLID_INK);\n}\n\nfunction renderBlock(selector: string, tokens: Record<string, string>): string {\n const entries = Object.entries(tokens);\n if (entries.length === 0) return \"\";\n const body = entries.map(([name, value]) => ` ${name}: ${value};`).join(\"\\n\");\n return `${selector} {\\n${body}\\n}`;\n}\n\n/**\n * Generate `--tempest-*` overrides from a small brand description.\n *\n * Only the families you pass are generated; everything else falls through to the\n * SDK's own tokens, so a theme stays a patch and not a fork of `colors.css`.\n *\n * @example\n * ```ts\n * import { applyTheme, createTheme } from \"tempest-react-sdk\";\n *\n * const theme = createTheme({\n * primary: \"#7c3aed\",\n * radius: \"lg\",\n * chart: [\"#7c3aed\", \"#0ea5e9\", \"#22c55e\", \"#f59e0b\"],\n * });\n *\n * applyTheme(theme);\n * ```\n *\n * @param options - Brand colors plus optional radius / chart / focus-ring tuning.\n * @returns The light and dark token maps and the CSS text that carries them.\n */\nexport function createTheme(options: CreateThemeOptions = {}): GeneratedTheme {\n const {\n primary,\n gray,\n chart,\n radius,\n focusRingAlpha,\n selector = \":root\",\n darkSelector = '[data-tempest-theme=\"dark\"]',\n inverse,\n inverseSelector = INVERSE_SELECTOR,\n } = options;\n\n warnOnTranslucentFocusRing(focusRingAlpha);\n\n const light: Record<string, string> = {};\n const dark: Record<string, string> = {};\n\n // `anchor: false`: a neutral ramp has to keep its tuned lightness curve.\n // Anchoring it at the input compressed both halves and dropped\n // text-muted-on-surface-3 to ~4.2:1 — below AA — which the browser axe\n // sweep caught on the generated themes.\n const grayScales = gray\n ? {\n light: createColorScale(gray, \"light\", { anchor: false, neutral: true }),\n dark: createColorScale(gray, \"dark\", { anchor: false, neutral: true }),\n }\n : undefined;\n\n if (primary) {\n const lightScale = createColorScale(primary, \"light\");\n const darkScale = createColorScale(primary, \"dark\");\n writeScale(light, \"primary\", lightScale);\n writeScale(dark, \"primary\", darkScale);\n writePrimaryAliases(\n light,\n lightScale,\n \"light\",\n surfacesOf(\"light\", grayScales),\n focusRingAlpha,\n );\n writePrimaryAliases(\n dark,\n darkScale,\n \"dark\",\n surfacesOf(\"dark\", grayScales),\n focusRingAlpha,\n );\n }\n\n if (grayScales) {\n writeScale(light, \"gray\", grayScales.light);\n writeScale(dark, \"gray\", grayScales.dark);\n writeNeutralAliases(light, grayScales.light, \"light\");\n writeNeutralAliases(dark, grayScales.dark, \"dark\");\n }\n\n for (const status of THEME_STATUSES) {\n const value = options[status];\n if (!value) continue;\n writeStatus(light, status, createColorScale(value, \"light\"), \"light\");\n writeStatus(dark, status, createColorScale(value, \"dark\"), \"dark\");\n }\n\n if (chart?.length) {\n chart.forEach((color, index) => {\n light[`--tempest-chart-${index + 1}`] = color;\n });\n // Declares how many series colors this theme owns. Without it the reader\n // keeps walking into the SDK's built-in `--tempest-chart-7`/`-8`, so a\n // 6-color brand palette silently mixes with two leftover defaults — which\n // is exactly what a 7-series chart would show.\n light[\"--tempest-chart-count\"] = String(chart.length);\n }\n\n /*\n * Continuous scales follow the brand too.\n *\n * Without this a rebranded app gets its categorical slots recoloured and then a\n * heatmap still painted in the SDK's blue — the one chart on the page that\n * silently ignores the brand. Both scales derive from the first series hue (or\n * the primary), stepped by perceptual lightness for each mode separately.\n *\n * Skipped entirely when the theme names no colour to derive from, so the\n * built-in tokens survive instead of being overwritten with a guess.\n */\n const scaleSource = chart?.[0] ?? primary;\n if (scaleSource) {\n const coolHue = hueOf(scaleSource);\n // The opposite pole: the brand's own danger colour when it has one, since a\n // diverging scale's warm arm and \"bad\" should not disagree on screen.\n const warmHue = options.danger ? hueOf(options.danger) : (coolHue + 180) % 360;\n for (const [target, mode] of [\n [light, \"light\"],\n [dark, \"dark\"],\n ] as const) {\n buildRamp(coolHue, mode).forEach((stepColor, index) => {\n target[`--tempest-chart-sequential-${index + 1}`] = stepColor;\n });\n const diverging = buildDivergingRamp({\n coolHue,\n warmHue,\n mid: mode === \"light\" ? \"#e4e7ec\" : \"#262d3f\",\n mode,\n });\n [...diverging.cool, diverging.mid, ...diverging.warm].forEach((stepColor, index) => {\n target[`--tempest-chart-diverging-${index + 1}`] = stepColor;\n });\n }\n }\n\n if (radius) {\n const steps = typeof radius === \"string\" ? RADIUS_PRESETS[radius] : radius;\n for (const [step, value] of Object.entries(steps)) {\n light[`--tempest-radius-${step}`] = value;\n }\n }\n\n const inverseSurface =\n primary && inverse\n ? inverse({\n primary,\n statuses: {\n success: options.success,\n warning: options.warning,\n danger: options.danger,\n info: options.info,\n },\n chart,\n selector: inverseSelector,\n page: { selector, darkSelector },\n })\n : null;\n\n const css = [\n renderBlock(selector, light),\n renderBlock(darkSelector, dark),\n inverseSurface ? renderInverseSurface(inverseSelector, inverseSurface) : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n return inverseSurface\n ? { light, dark, inverse: inverseSurface.tokens, css }\n : { light, dark, css };\n}\n\n/**\n * Contrast ratio of `--tempest-primary-foreground` over the brand color.\n *\n * Exposed so an app (or a test) can assert its own brand clears WCAG AA (4.5) for\n * body text or AA-large (3.0) for button labels, instead of trusting the pick.\n *\n * @param options - The same input given to {@link createTheme}.\n * @returns The ratio, or `null` when no `primary` was provided.\n */\nexport function themeContrast(options: CreateThemeOptions): number | null {\n if (!options.primary) return null;\n const scale = createColorScale(options.primary, \"light\");\n return contrastRatio(scale[500], readableForeground(scale[500]));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"create-theme.cjs","names":["contrastRatio","isDevBuild","readableForeground","hexToRgbaString","ON_SOLID_INK","INVERSE_SELECTOR","createColorScale","THEME_STATUSES","hueOf","buildDivergingRamp","renderInverseSurface","require_dev_mode","require_color","require_data_viz_ramps","require_inverse_render","require_status_tokens","RADIUS_PRESETS","SCALE_STEPS","writeScale","step","name","scale","AA_TEXT_CONTRAST","pickOnSoftStep","candidates","softStep","INDICATOR_CONTRAST","SDK_SURFACES","FOCUS_RING_CANDIDATES","pickFocusRingStep","worstCase","surfaces","surface","best","bestRatio","measured","surfacesOf","grayScales","scheme","warnOnTranslucentFocusRing","focusRingAlpha","writePrimaryAliases","foreground","ring","writeNeutralAliases","renderBlock","entries","tokens","selector","value","createTheme","options","light","dark","gray","primary","lightScale","darkScale","status","chart","index","color","scaleSource","coolHue","warmHue","target","mode","stepColor","diverging","radius","steps","inverseSurface","inverse","inverseSelector","css","darkSelector","themeContrast"],"sources":["../../src/theme/create-theme.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — one pass that emits the whole token set — surfaces,\n * text, borders, states, the chart ramps — for both modes, with every value checked\n * against the surface it will sit on. The checks are what make the length: each\n * token is derived and then verified against the same background table.\n */\n/**\n * Theme factory: turns a handful of brand colors into the full set of\n * `--tempest-*` token overrides, for both light and dark.\n *\n * Rebranding used to mean hand-writing ~167 custom properties (and getting the\n * dark ramp inversion right by hand). `createTheme({ primary: \"#7c3aed\" })`\n * emits the same thing, derived in OKLCH so the ramp stays perceptually even.\n */\nimport {\n contrastRatio,\n createColorScale,\n hexToRgbaString,\n readableForeground,\n type ColorScale,\n type ScaleStep,\n} from \"./color\";\nimport { buildDivergingRamp, buildRamp, hueOf } from \"./data-viz-ramps\";\nimport { isDevBuild } from \"../utils/dev-mode\";\nimport {\n INVERSE_SELECTOR,\n renderInverseSurface,\n type InverseSurfaceGenerator,\n} from \"./inverse-render\";\nimport { ON_SOLID_INK, THEME_STATUSES, writeStatus } from \"./status-tokens\";\n\n/** Radius presets, applied to the whole `--tempest-radius-*` family at once. */\nexport type ThemeRadius = \"none\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\";\n\nexport type { ThemeStatus } from \"./status-tokens\";\n\n/** Input for {@link createTheme}. Every field is optional — omitted families keep the built-in tokens. */\nexport interface CreateThemeOptions {\n /** Brand color, used as the `500` step of the primary scale. */\n primary?: string;\n /** Neutral color, used as the `500` step of the gray scale (surfaces, borders, text). */\n gray?: string;\n /** Success color (`--tempest-success*`). */\n success?: string;\n /** Warning color (`--tempest-warning*`). */\n warning?: string;\n /** Danger color (`--tempest-danger*`). */\n danger?: string;\n /** Info color (`--tempest-info*`). */\n info?: string;\n /**\n * Categorical series colors for `tempest-react-sdk/charts`, in cycle order.\n * Written to `--tempest-chart-1` … `--tempest-chart-N`, so charts follow the\n * theme instead of a hardcoded palette.\n */\n chart?: string[];\n /** Corner radius scale. A preset name, or explicit per-step values. */\n radius?: ThemeRadius | Partial<Record<\"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\", string>>;\n /**\n * Opacity of `--tempest-focus-ring-color`. Omit it — the default ring is opaque.\n *\n * A translucent ring has no contrast of its own; it has the contrast of\n * whatever it composites over. Passing a value below `1` reintroduces the\n * failure 0.61.0 fixed in the built-in tokens, and logs a warning in a\n * development build. Kept because a translucent ring over a background you\n * control is a legitimate choice.\n */\n focusRingAlpha?: number;\n /** Selector the light tokens are written under. Default `\":root\"`. */\n selector?: string;\n /** Selector the dark tokens are written under. Default `'[data-tempest-theme=\"dark\"]'`. */\n darkSelector?: string;\n /**\n * Also emit the inverse surface — the token set for a section painted in the\n * brand color — by passing its generator, `createInverseSurface`. Off by\n * default; ignored without `primary`.\n *\n * The generator is passed in rather than switched on with `true` so that\n * `createTheme` never imports it: an app that does not paint a section in\n * its brand does not ship the 1.68 kB brotli it costs.\n *\n * @example\n * ```ts\n * import { createInverseSurface, createTheme } from \"tempest-react-sdk\";\n *\n * createTheme({ primary: \"#03184b\", inverse: createInverseSurface });\n * ```\n */\n inverse?: InverseSurfaceGenerator;\n /** Selector the inverse tokens are written under. Default `'[data-tempest-tone=\"inverse\"]'`. */\n inverseSelector?: string;\n}\n\n/** A generated theme: token maps per color scheme, plus the CSS text that carries them. */\nexport interface GeneratedTheme {\n /** Light-scheme custom properties, without the leading `--`-less names (keys include `--`). */\n light: Record<string, string>;\n /** Dark-scheme custom properties. */\n dark: Record<string, string>;\n /**\n * Inverse-surface custom properties — literal colors, identical under the\n * light and the dark page scheme. Present only when the theme names a\n * `primary` and passes `inverse`.\n */\n inverse?: Record<string, string>;\n /** Both blocks rendered as CSS, ready for {@link applyTheme} or a stylesheet. */\n css: string;\n}\n\nconst RADIUS_PRESETS: Record<ThemeRadius, Record<string, string>> = {\n none: { xs: \"0\", sm: \"0\", md: \"0\", lg: \"0\", xl: \"0\", \"2xl\": \"0\" },\n sm: { xs: \"1px\", sm: \"2px\", md: \"4px\", lg: \"6px\", xl: \"8px\", \"2xl\": \"12px\" },\n md: { xs: \"2px\", sm: \"4px\", md: \"8px\", lg: \"12px\", xl: \"16px\", \"2xl\": \"24px\" },\n lg: { xs: \"4px\", sm: \"6px\", md: \"12px\", lg: \"16px\", xl: \"22px\", \"2xl\": \"32px\" },\n xl: { xs: \"6px\", sm: \"10px\", md: \"16px\", lg: \"24px\", xl: \"32px\", \"2xl\": \"44px\" },\n full: { xs: \"4px\", sm: \"8px\", md: \"9999px\", lg: \"9999px\", xl: \"9999px\", \"2xl\": \"9999px\" },\n};\n\nconst SCALE_STEPS: ScaleStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\n\nfunction writeScale(tokens: Record<string, string>, name: string, scale: ColorScale): void {\n for (const step of SCALE_STEPS) {\n tokens[`--tempest-${name}-${step}`] = scale[step];\n }\n}\n\n/** Minimum contrast for body text, WCAG 2.x AA. */\nconst AA_TEXT_CONTRAST = 4.5;\n\n/**\n * Choose the ramp step for text sitting on the soft tint.\n *\n * A fixed step does not survive an arbitrary brand color: the built-in blue only\n * reaches 4.37:1 at `500` over its own `50` tint, and a generated emerald lands\n * at 4.41:1 at `600` — both fail AA for body text by a hair. So the step is\n * picked by measuring, walking away from the tint until it clears AA, and\n * falling back to the most extreme candidate when even that cannot (a very light\n * or very desaturated brand).\n *\n * @param scale - The generated ramp.\n * @param softStep - Step used as `--tempest-primary-soft`.\n * @param candidates - Steps to try, in order of preference.\n * @returns The first candidate clearing {@link AA_TEXT_CONTRAST}, else the last.\n */\nfunction pickOnSoftStep(\n scale: ColorScale,\n softStep: ScaleStep,\n candidates: ScaleStep[],\n): ScaleStep {\n for (const step of candidates) {\n if (contrastRatio(scale[softStep], scale[step]) >= AA_TEXT_CONTRAST) return step;\n }\n return candidates[candidates.length - 1];\n}\n\n/** Minimum contrast for a non-text indicator, WCAG 2.2 SC 1.4.11. */\nconst INDICATOR_CONTRAST = 3;\n\n/**\n * The four surfaces a focus ring can land on, as the SDK's own `colors.css`\n * paints them.\n *\n * Ported from `src/styles/colors.css` (`--tempest-bg`, `--tempest-surface`,\n * `--tempest-surface-2`, `--tempest-surface-3`, resolved through the gray ramp),\n * and pinned by a test that reads that file — a theme that only names `primary`\n * keeps these, so the ring has to be measured against them and not against a\n * guess. The light values resolve through `--tempest-gray-50/100/200`; the dark\n * ones are literals in the dark block.\n */\nconst SDK_SURFACES: Record<\"light\" | \"dark\", readonly string[]> = {\n light: [\"#ffffff\", \"#f8f9fb\", \"#f1f3f6\", \"#e4e7ec\"],\n dark: [\"#0b0d12\", \"#14171f\", \"#1d2230\", \"#262d3f\"],\n};\n\n/**\n * Ramp steps to try for the focus ring, in order.\n *\n * `500` first, because the ring should read as the brand when it can, then up\n * the ramp — which moves away from the surfaces in **both** schemes, because\n * `createColorScale` inverts the dark ramp: there `50` is the darkest step (it\n * is what `--tempest-bg` is made of) and `900` the lightest. Walking down in\n * dark mode looks like the right inversion and is the wrong direction; measured,\n * it left a near-black brand's ring at 1.04:1 over its own background.\n */\nconst FOCUS_RING_CANDIDATES: readonly ScaleStep[] = [500, 600, 700, 800, 900];\n\n/**\n * Choose the ramp step for the focus ring, by measuring it against the surfaces\n * it will actually be drawn on.\n *\n * A fixed step does not survive an arbitrary brand, and the measurement says so\n * loudly: of twelve brands checked against the four surfaces in both schemes —\n * 96 pairings — `500` opaque clears 3:1 in 58 of them, and `500` at the old\n * default alpha of 0.35 in 3. Picking the step by measurement clears all 96. The\n * brand from the report that opened this\n * (`#8100D7`) passes in light at 7.20:1 and fails in **dark** at 2.70:1 down to\n * 1.91:1 on `surface-3`; a yellow fails in light at 1.43:1. So the step is\n * picked the way {@link pickOnSoftStep} picks text on a tint: walk away from the\n * surfaces until the ring clears the floor against *all* of them.\n *\n * The fallback is the candidate with the best worst case rather than the last\n * one, because \"the most extreme step\" is not always the most contrasting one\n * once a brand is near-neutral.\n *\n * @param scale - The generated ramp.\n * @param surfaces - The four surfaces this theme will paint, opaque hex.\n * @returns The first candidate clearing {@link INDICATOR_CONTRAST} on every\n * surface, else the candidate whose weakest pairing is strongest.\n */\nfunction pickFocusRingStep(scale: ColorScale, surfaces: readonly string[]): ScaleStep {\n const worstCase = (step: ScaleStep): number =>\n Math.min(...surfaces.map((surface) => contrastRatio(scale[step], surface)));\n let best: ScaleStep = FOCUS_RING_CANDIDATES[0] as ScaleStep;\n let bestRatio = -1;\n for (const step of FOCUS_RING_CANDIDATES) {\n const measured = worstCase(step);\n if (measured >= INDICATOR_CONTRAST) return step;\n if (measured > bestRatio) {\n best = step;\n bestRatio = measured;\n }\n }\n return best;\n}\n\n/**\n * The surfaces this theme will actually paint, per scheme.\n *\n * A theme that names `gray` repaints all four, so measuring the ring against the\n * SDK's would be measuring the wrong backdrop — and a theme that does not keeps\n * the SDK's, which is the common case. The order and the ramp steps mirror\n * {@link writeNeutralAliases}, which is what emits them.\n *\n * @param scheme - Which scheme is being emitted.\n * @param grayScales - The generated neutral ramps, when the theme names one.\n * @returns Four opaque hex colors: bg, surface, surface-2, surface-3.\n */\nfunction surfacesOf(\n scheme: \"light\" | \"dark\",\n grayScales: { light: ColorScale; dark: ColorScale } | undefined,\n): readonly string[] {\n if (!grayScales) return SDK_SURFACES[scheme];\n const scale = grayScales[scheme];\n return scheme === \"light\"\n ? [\"#ffffff\", scale[50], scale[100], scale[200]]\n : [scale[50], scale[100], scale[200], scale[300]];\n}\n\n/**\n * Warn, in a development build, that an alpha was asked for the focus ring.\n *\n * A translucent ring has no contrast of its own — it has the contrast of\n * whatever it composites over — and that is the failure this option used to\n * ship by default: measured at alpha `0.35`, twelve brands across four surfaces\n * and both schemes produced 96 pairings, of which 3 cleared the 3:1 of WCAG 2.2\n * SC 1.4.11. It stays available, because a translucent ring over a\n * known background is a legitimate choice, but it is a choice a theme now has to\n * make on purpose.\n *\n * The warning is the difficult part to notice otherwise: a failing focus ring is\n * visible, it just does not separate.\n *\n * @param focusRingAlpha - The opacity the caller asked for, if any.\n */\nfunction warnOnTranslucentFocusRing(focusRingAlpha: number | undefined): void {\n if (focusRingAlpha === undefined || focusRingAlpha >= 1) return;\n if (!isDevBuild()) return;\n console.warn(\n `[tempest-react-sdk] createTheme({ focusRingAlpha: ${focusRingAlpha} }) makes the focus ring ` +\n \"translucent, so its contrast becomes whatever it composites over — measured below the 3:1 \" +\n \"of WCAG 2.2 SC 1.4.11 on every surface the SDK paints. Drop the option to get the opaque \" +\n \"ring, which is derived from your brand ramp and measured against those surfaces.\",\n );\n}\n\n/**\n * Emit the primary aliases for one scheme.\n *\n * The dark scheme walks the ramp the other way (hover is *lighter*, the soft\n * tint is a dark shade, and readable text on that tint is a light shade) — the\n * same inversion the built-in `colors.css` dark block does by hand.\n *\n * The selected-state indicator is derived from the same measurement as the focus\n * ring and emitted as its own token. It never takes `focusRingAlpha`: a\n * translucent ring over a known background is a legitimate choice a theme can\n * make, while a translucent *state* indicator has the contrast of whatever it\n * composites over, which is the defect this token exists to end.\n *\n * @param tokens - The token map for this scheme, written in place.\n * @param scale - The generated primary ramp.\n * @param scheme - Which scheme is being emitted.\n * @param surfaces - The surfaces this theme paints, for the focus-ring measurement.\n * @param focusRingAlpha - Opacity asked for the ring, or `undefined` for opaque.\n */\nfunction writePrimaryAliases(\n tokens: Record<string, string>,\n scale: ColorScale,\n scheme: \"light\" | \"dark\",\n surfaces: readonly string[],\n focusRingAlpha: number | undefined,\n): void {\n tokens[\"--tempest-primary\"] = \"var(--tempest-primary-500)\";\n if (scheme === \"light\") {\n tokens[\"--tempest-primary-hover\"] = \"var(--tempest-primary-600)\";\n tokens[\"--tempest-primary-active\"] = \"var(--tempest-primary-700)\";\n tokens[\"--tempest-primary-soft\"] = \"var(--tempest-primary-50)\";\n tokens[\"--tempest-primary-soft-hover\"] = \"var(--tempest-primary-100)\";\n tokens[\"--tempest-primary-on-soft\"] =\n `var(--tempest-primary-${pickOnSoftStep(scale, 50, [600, 700, 800, 900])})`;\n } else {\n tokens[\"--tempest-primary-hover\"] = \"var(--tempest-primary-400)\";\n tokens[\"--tempest-primary-active\"] = \"var(--tempest-primary-300)\";\n tokens[\"--tempest-primary-soft\"] = \"var(--tempest-primary-100)\";\n tokens[\"--tempest-primary-soft-hover\"] = \"var(--tempest-primary-200)\";\n tokens[\"--tempest-primary-on-soft\"] =\n `var(--tempest-primary-${pickOnSoftStep(scale, 100, [700, 800, 900])})`;\n }\n\n const foreground = readableForeground(scale[500]);\n tokens[\"--tempest-primary-foreground\"] = foreground;\n tokens[\"--tempest-text-on-primary\"] = foreground;\n const ring = scale[pickFocusRingStep(scale, surfaces)];\n tokens[\"--tempest-focus-ring-color\"] =\n focusRingAlpha === undefined || focusRingAlpha >= 1\n ? ring\n : hexToRgbaString(ring, focusRingAlpha);\n tokens[\"--tempest-selected-indicator\"] = ring;\n}\n\n/**\n * Emit the neutral surface/border/text aliases from a generated gray scale.\n *\n * `--tempest-bg` is pushed past the ramp on purpose: pure white in light mode and\n * a shade darker than `gray-50` in dark mode, so a raised surface still reads as\n * raised against the page.\n */\nfunction writeNeutralAliases(\n tokens: Record<string, string>,\n scale: ColorScale,\n scheme: \"light\" | \"dark\",\n): void {\n if (scheme === \"light\") {\n tokens[\"--tempest-bg\"] = \"#ffffff\";\n tokens[\"--tempest-surface\"] = \"var(--tempest-gray-50)\";\n tokens[\"--tempest-surface-2\"] = \"var(--tempest-gray-100)\";\n tokens[\"--tempest-surface-3\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-border\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-border-strong\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-text\"] = \"var(--tempest-gray-900)\";\n tokens[\"--tempest-text-muted\"] = \"var(--tempest-gray-600)\";\n tokens[\"--tempest-text-subtle\"] = \"var(--tempest-gray-500)\";\n } else {\n tokens[\"--tempest-bg\"] = scale[50];\n tokens[\"--tempest-surface\"] = \"var(--tempest-gray-100)\";\n tokens[\"--tempest-surface-2\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-surface-3\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-border\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-border-strong\"] = \"var(--tempest-gray-400)\";\n tokens[\"--tempest-text\"] = \"var(--tempest-gray-900)\";\n tokens[\"--tempest-text-muted\"] = \"var(--tempest-gray-700)\";\n tokens[\"--tempest-text-subtle\"] = \"var(--tempest-gray-600)\";\n }\n tokens[\"--tempest-neutral-on-solid\"] = readableForeground(scale[700], \"#ffffff\", ON_SOLID_INK);\n}\n\nfunction renderBlock(selector: string, tokens: Record<string, string>): string {\n const entries = Object.entries(tokens);\n if (entries.length === 0) return \"\";\n const body = entries.map(([name, value]) => ` ${name}: ${value};`).join(\"\\n\");\n return `${selector} {\\n${body}\\n}`;\n}\n\n/**\n * Generate `--tempest-*` overrides from a small brand description.\n *\n * Only the families you pass are generated; everything else falls through to the\n * SDK's own tokens, so a theme stays a patch and not a fork of `colors.css`.\n *\n * @example\n * ```ts\n * import { applyTheme, createTheme } from \"tempest-react-sdk\";\n *\n * const theme = createTheme({\n * primary: \"#7c3aed\",\n * radius: \"lg\",\n * chart: [\"#7c3aed\", \"#0ea5e9\", \"#22c55e\", \"#f59e0b\"],\n * });\n *\n * applyTheme(theme);\n * ```\n *\n * @param options - Brand colors plus optional radius / chart / focus-ring tuning.\n * @returns The light and dark token maps and the CSS text that carries them.\n */\nexport function createTheme(options: CreateThemeOptions = {}): GeneratedTheme {\n const {\n primary,\n gray,\n chart,\n radius,\n focusRingAlpha,\n selector = \":root\",\n darkSelector = '[data-tempest-theme=\"dark\"]',\n inverse,\n inverseSelector = INVERSE_SELECTOR,\n } = options;\n\n warnOnTranslucentFocusRing(focusRingAlpha);\n\n const light: Record<string, string> = {};\n const dark: Record<string, string> = {};\n\n // `anchor: false`: a neutral ramp has to keep its tuned lightness curve.\n // Anchoring it at the input compressed both halves and dropped\n // text-muted-on-surface-3 to ~4.2:1 — below AA — which the browser axe\n // sweep caught on the generated themes.\n const grayScales = gray\n ? {\n light: createColorScale(gray, \"light\", { anchor: false, neutral: true }),\n dark: createColorScale(gray, \"dark\", { anchor: false, neutral: true }),\n }\n : undefined;\n\n if (primary) {\n const lightScale = createColorScale(primary, \"light\");\n const darkScale = createColorScale(primary, \"dark\");\n writeScale(light, \"primary\", lightScale);\n writeScale(dark, \"primary\", darkScale);\n writePrimaryAliases(\n light,\n lightScale,\n \"light\",\n surfacesOf(\"light\", grayScales),\n focusRingAlpha,\n );\n writePrimaryAliases(\n dark,\n darkScale,\n \"dark\",\n surfacesOf(\"dark\", grayScales),\n focusRingAlpha,\n );\n }\n\n if (grayScales) {\n writeScale(light, \"gray\", grayScales.light);\n writeScale(dark, \"gray\", grayScales.dark);\n writeNeutralAliases(light, grayScales.light, \"light\");\n writeNeutralAliases(dark, grayScales.dark, \"dark\");\n }\n\n for (const status of THEME_STATUSES) {\n const value = options[status];\n if (!value) continue;\n writeStatus(light, status, createColorScale(value, \"light\"), \"light\");\n writeStatus(dark, status, createColorScale(value, \"dark\"), \"dark\");\n }\n\n if (chart?.length) {\n chart.forEach((color, index) => {\n light[`--tempest-chart-${index + 1}`] = color;\n });\n // Declares how many series colors this theme owns. Without it the reader\n // keeps walking into the SDK's built-in `--tempest-chart-7`/`-8`, so a\n // 6-color brand palette silently mixes with two leftover defaults — which\n // is exactly what a 7-series chart would show.\n light[\"--tempest-chart-count\"] = String(chart.length);\n }\n\n /*\n * Continuous scales follow the brand too.\n *\n * Without this a rebranded app gets its categorical slots recoloured and then a\n * heatmap still painted in the SDK's blue — the one chart on the page that\n * silently ignores the brand. Both scales derive from the first series hue (or\n * the primary), stepped by perceptual lightness for each mode separately.\n *\n * Skipped entirely when the theme names no colour to derive from, so the\n * built-in tokens survive instead of being overwritten with a guess.\n */\n const scaleSource = chart?.[0] ?? primary;\n if (scaleSource) {\n const coolHue = hueOf(scaleSource);\n // The opposite pole: the brand's own danger colour when it has one, since a\n // diverging scale's warm arm and \"bad\" should not disagree on screen.\n const warmHue = options.danger ? hueOf(options.danger) : (coolHue + 180) % 360;\n for (const [target, mode] of [\n [light, \"light\"],\n [dark, \"dark\"],\n ] as const) {\n buildRamp(coolHue, mode).forEach((stepColor, index) => {\n target[`--tempest-chart-sequential-${index + 1}`] = stepColor;\n });\n const diverging = buildDivergingRamp({\n coolHue,\n warmHue,\n mid: mode === \"light\" ? \"#e4e7ec\" : \"#262d3f\",\n mode,\n });\n [...diverging.cool, diverging.mid, ...diverging.warm].forEach((stepColor, index) => {\n target[`--tempest-chart-diverging-${index + 1}`] = stepColor;\n });\n }\n }\n\n if (radius) {\n const steps = typeof radius === \"string\" ? RADIUS_PRESETS[radius] : radius;\n for (const [step, value] of Object.entries(steps)) {\n light[`--tempest-radius-${step}`] = value;\n }\n }\n\n const inverseSurface =\n primary && inverse\n ? inverse({\n primary,\n statuses: {\n success: options.success,\n warning: options.warning,\n danger: options.danger,\n info: options.info,\n },\n chart,\n selector: inverseSelector,\n page: { selector, darkSelector },\n })\n : null;\n\n const css = [\n renderBlock(selector, light),\n renderBlock(darkSelector, dark),\n inverseSurface ? renderInverseSurface(inverseSelector, inverseSurface) : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n return inverseSurface\n ? { light, dark, inverse: inverseSurface.tokens, css }\n : { light, dark, css };\n}\n\n/**\n * Contrast ratio of `--tempest-primary-foreground` over the brand color.\n *\n * Exposed so an app (or a test) can assert its own brand clears WCAG AA (4.5) for\n * body text or AA-large (3.0) for button labels, instead of trusting the pick.\n *\n * @param options - The same input given to {@link createTheme}.\n * @returns The ratio, or `null` when no `primary` was provided.\n */\nexport function themeContrast(options: CreateThemeOptions): number | null {\n if (!options.primary) return null;\n const scale = createColorScale(options.primary, \"light\");\n return contrastRatio(scale[500], readableForeground(scale[500]));\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-theme.js","names":[],"sources":["../../src/theme/create-theme.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — one pass that emits the whole token set — surfaces,\n * text, borders, states, the chart ramps — for both modes, with every value checked\n * against the surface it will sit on. The checks are what make the length: each\n * token is derived and then verified against the same background table.\n */\n/**\n * Theme factory: turns a handful of brand colors into the full set of\n * `--tempest-*` token overrides, for both light and dark.\n *\n * Rebranding used to mean hand-writing ~167 custom properties (and getting the\n * dark ramp inversion right by hand). `createTheme({ primary: \"#7c3aed\" })`\n * emits the same thing, derived in OKLCH so the ramp stays perceptually even.\n */\nimport {\n contrastRatio,\n createColorScale,\n hexToRgbaString,\n readableForeground,\n type ColorScale,\n type ScaleStep,\n} from \"./color\";\nimport { buildDivergingRamp, buildRamp, hueOf } from \"./data-viz-ramps\";\nimport { isDevBuild } from \"../utils/dev-mode\";\nimport {\n INVERSE_SELECTOR,\n renderInverseSurface,\n type InverseSurfaceGenerator,\n} from \"./inverse-render\";\nimport { ON_SOLID_INK, THEME_STATUSES, writeStatus } from \"./status-tokens\";\n\n/** Radius presets, applied to the whole `--tempest-radius-*` family at once. */\nexport type ThemeRadius = \"none\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\";\n\nexport type { ThemeStatus } from \"./status-tokens\";\n\n/** Input for {@link createTheme}. Every field is optional — omitted families keep the built-in tokens. */\nexport interface CreateThemeOptions {\n /** Brand color, used as the `500` step of the primary scale. */\n primary?: string;\n /** Neutral color, used as the `500` step of the gray scale (surfaces, borders, text). */\n gray?: string;\n /** Success color (`--tempest-success*`). */\n success?: string;\n /** Warning color (`--tempest-warning*`). */\n warning?: string;\n /** Danger color (`--tempest-danger*`). */\n danger?: string;\n /** Info color (`--tempest-info*`). */\n info?: string;\n /**\n * Categorical series colors for `tempest-react-sdk/charts`, in cycle order.\n * Written to `--tempest-chart-1` … `--tempest-chart-N`, so charts follow the\n * theme instead of a hardcoded palette.\n */\n chart?: string[];\n /** Corner radius scale. A preset name, or explicit per-step values. */\n radius?: ThemeRadius | Partial<Record<\"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\", string>>;\n /**\n * Opacity of `--tempest-focus-ring-color`. Omit it — the default ring is opaque.\n *\n * A translucent ring has no contrast of its own; it has the contrast of\n * whatever it composites over. Passing a value below `1` reintroduces the\n * failure 0.61.0 fixed in the built-in tokens, and logs a warning in a\n * development build. Kept because a translucent ring over a background you\n * control is a legitimate choice.\n */\n focusRingAlpha?: number;\n /** Selector the light tokens are written under. Default `\":root\"`. */\n selector?: string;\n /** Selector the dark tokens are written under. Default `'[data-tempest-theme=\"dark\"]'`. */\n darkSelector?: string;\n /**\n * Also emit the inverse surface — the token set for a section painted in the\n * brand color — by passing its generator, `createInverseSurface`. Off by\n * default; ignored without `primary`.\n *\n * The generator is passed in rather than switched on with `true` so that\n * `createTheme` never imports it: an app that does not paint a section in\n * its brand does not ship the 1.68 kB brotli it costs.\n *\n * @example\n * ```ts\n * import { createInverseSurface, createTheme } from \"tempest-react-sdk\";\n *\n * createTheme({ primary: \"#03184b\", inverse: createInverseSurface });\n * ```\n */\n inverse?: InverseSurfaceGenerator;\n /** Selector the inverse tokens are written under. Default `'[data-tempest-tone=\"inverse\"]'`. */\n inverseSelector?: string;\n}\n\n/** A generated theme: token maps per color scheme, plus the CSS text that carries them. */\nexport interface GeneratedTheme {\n /** Light-scheme custom properties, without the leading `--`-less names (keys include `--`). */\n light: Record<string, string>;\n /** Dark-scheme custom properties. */\n dark: Record<string, string>;\n /**\n * Inverse-surface custom properties — literal colors, identical under the\n * light and the dark page scheme. Present only when the theme names a\n * `primary` and passes `inverse`.\n */\n inverse?: Record<string, string>;\n /** Both blocks rendered as CSS, ready for {@link applyTheme} or a stylesheet. */\n css: string;\n}\n\nconst RADIUS_PRESETS: Record<ThemeRadius, Record<string, string>> = {\n none: { xs: \"0\", sm: \"0\", md: \"0\", lg: \"0\", xl: \"0\", \"2xl\": \"0\" },\n sm: { xs: \"1px\", sm: \"2px\", md: \"4px\", lg: \"6px\", xl: \"8px\", \"2xl\": \"12px\" },\n md: { xs: \"2px\", sm: \"4px\", md: \"8px\", lg: \"12px\", xl: \"16px\", \"2xl\": \"24px\" },\n lg: { xs: \"4px\", sm: \"6px\", md: \"12px\", lg: \"16px\", xl: \"22px\", \"2xl\": \"32px\" },\n xl: { xs: \"6px\", sm: \"10px\", md: \"16px\", lg: \"24px\", xl: \"32px\", \"2xl\": \"44px\" },\n full: { xs: \"4px\", sm: \"8px\", md: \"9999px\", lg: \"9999px\", xl: \"9999px\", \"2xl\": \"9999px\" },\n};\n\nconst SCALE_STEPS: ScaleStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\n\nfunction writeScale(tokens: Record<string, string>, name: string, scale: ColorScale): void {\n for (const step of SCALE_STEPS) {\n tokens[`--tempest-${name}-${step}`] = scale[step];\n }\n}\n\n/** Minimum contrast for body text, WCAG 2.x AA. */\nconst AA_TEXT_CONTRAST = 4.5;\n\n/**\n * Choose the ramp step for text sitting on the soft tint.\n *\n * A fixed step does not survive an arbitrary brand color: the built-in blue only\n * reaches 4.37:1 at `500` over its own `50` tint, and a generated emerald lands\n * at 4.41:1 at `600` — both fail AA for body text by a hair. So the step is\n * picked by measuring, walking away from the tint until it clears AA, and\n * falling back to the most extreme candidate when even that cannot (a very light\n * or very desaturated brand).\n *\n * @param scale - The generated ramp.\n * @param softStep - Step used as `--tempest-primary-soft`.\n * @param candidates - Steps to try, in order of preference.\n * @returns The first candidate clearing {@link AA_TEXT_CONTRAST}, else the last.\n */\nfunction pickOnSoftStep(\n scale: ColorScale,\n softStep: ScaleStep,\n candidates: ScaleStep[],\n): ScaleStep {\n for (const step of candidates) {\n if (contrastRatio(scale[softStep], scale[step]) >= AA_TEXT_CONTRAST) return step;\n }\n return candidates[candidates.length - 1];\n}\n\n/** Minimum contrast for a non-text indicator, WCAG 2.2 SC 1.4.11. */\nconst INDICATOR_CONTRAST = 3;\n\n/**\n * The four surfaces a focus ring can land on, as the SDK's own `colors.css`\n * paints them.\n *\n * Ported from `src/styles/colors.css` (`--tempest-bg`, `--tempest-surface`,\n * `--tempest-surface-2`, `--tempest-surface-3`, resolved through the gray ramp),\n * and pinned by a test that reads that file — a theme that only names `primary`\n * keeps these, so the ring has to be measured against them and not against a\n * guess. The light values resolve through `--tempest-gray-50/100/200`; the dark\n * ones are literals in the dark block.\n */\nconst SDK_SURFACES: Record<\"light\" | \"dark\", readonly string[]> = {\n light: [\"#ffffff\", \"#f8f9fb\", \"#f1f3f6\", \"#e4e7ec\"],\n dark: [\"#0b0d12\", \"#14171f\", \"#1d2230\", \"#262d3f\"],\n};\n\n/**\n * Ramp steps to try for the focus ring, in order.\n *\n * `500` first, because the ring should read as the brand when it can, then up\n * the ramp — which moves away from the surfaces in **both** schemes, because\n * `createColorScale` inverts the dark ramp: there `50` is the darkest step (it\n * is what `--tempest-bg` is made of) and `900` the lightest. Walking down in\n * dark mode looks like the right inversion and is the wrong direction; measured,\n * it left a near-black brand's ring at 1.04:1 over its own background.\n */\nconst FOCUS_RING_CANDIDATES: readonly ScaleStep[] = [500, 600, 700, 800, 900];\n\n/**\n * Choose the ramp step for the focus ring, by measuring it against the surfaces\n * it will actually be drawn on.\n *\n * A fixed step does not survive an arbitrary brand, and the measurement says so\n * loudly: of twelve brands checked against the four surfaces in both schemes —\n * 96 pairings — `500` opaque clears 3:1 in 58 of them, and `500` at the old\n * default alpha of 0.35 in 3. Picking the step by measurement clears all 96. The\n * brand from the report that opened this\n * (`#8100D7`) passes in light at 7.20:1 and fails in **dark** at 2.70:1 down to\n * 1.91:1 on `surface-3`; a yellow fails in light at 1.43:1. So the step is\n * picked the way {@link pickOnSoftStep} picks text on a tint: walk away from the\n * surfaces until the ring clears the floor against *all* of them.\n *\n * The fallback is the candidate with the best worst case rather than the last\n * one, because \"the most extreme step\" is not always the most contrasting one\n * once a brand is near-neutral.\n *\n * @param scale - The generated ramp.\n * @param surfaces - The four surfaces this theme will paint, opaque hex.\n * @returns The first candidate clearing {@link INDICATOR_CONTRAST} on every\n * surface, else the candidate whose weakest pairing is strongest.\n */\nfunction pickFocusRingStep(scale: ColorScale, surfaces: readonly string[]): ScaleStep {\n const worstCase = (step: ScaleStep): number =>\n Math.min(...surfaces.map((surface) => contrastRatio(scale[step], surface)));\n let best: ScaleStep = FOCUS_RING_CANDIDATES[0] as ScaleStep;\n let bestRatio = -1;\n for (const step of FOCUS_RING_CANDIDATES) {\n const measured = worstCase(step);\n if (measured >= INDICATOR_CONTRAST) return step;\n if (measured > bestRatio) {\n best = step;\n bestRatio = measured;\n }\n }\n return best;\n}\n\n/**\n * The surfaces this theme will actually paint, per scheme.\n *\n * A theme that names `gray` repaints all four, so measuring the ring against the\n * SDK's would be measuring the wrong backdrop — and a theme that does not keeps\n * the SDK's, which is the common case. The order and the ramp steps mirror\n * {@link writeNeutralAliases}, which is what emits them.\n *\n * @param scheme - Which scheme is being emitted.\n * @param grayScales - The generated neutral ramps, when the theme names one.\n * @returns Four opaque hex colors: bg, surface, surface-2, surface-3.\n */\nfunction surfacesOf(\n scheme: \"light\" | \"dark\",\n grayScales: { light: ColorScale; dark: ColorScale } | undefined,\n): readonly string[] {\n if (!grayScales) return SDK_SURFACES[scheme];\n const scale = grayScales[scheme];\n return scheme === \"light\"\n ? [\"#ffffff\", scale[50], scale[100], scale[200]]\n : [scale[50], scale[100], scale[200], scale[300]];\n}\n\n/**\n * Warn, in a development build, that an alpha was asked for the focus ring.\n *\n * A translucent ring has no contrast of its own — it has the contrast of\n * whatever it composites over — and that is the failure this option used to\n * ship by default: measured at alpha `0.35`, twelve brands across four surfaces\n * and both schemes produced 96 pairings, of which 3 cleared the 3:1 of WCAG 2.2\n * SC 1.4.11. It stays available, because a translucent ring over a\n * known background is a legitimate choice, but it is a choice a theme now has to\n * make on purpose.\n *\n * The warning is the difficult part to notice otherwise: a failing focus ring is\n * visible, it just does not separate.\n *\n * @param focusRingAlpha - The opacity the caller asked for, if any.\n */\nfunction warnOnTranslucentFocusRing(focusRingAlpha: number | undefined): void {\n if (focusRingAlpha === undefined || focusRingAlpha >= 1) return;\n if (!isDevBuild()) return;\n console.warn(\n `[tempest-react-sdk] createTheme({ focusRingAlpha: ${focusRingAlpha} }) makes the focus ring ` +\n \"translucent, so its contrast becomes whatever it composites over — measured below the 3:1 \" +\n \"of WCAG 2.2 SC 1.4.11 on every surface the SDK paints. Drop the option to get the opaque \" +\n \"ring, which is derived from your brand ramp and measured against those surfaces.\",\n );\n}\n\n/**\n * Emit the primary aliases for one scheme.\n *\n * The dark scheme walks the ramp the other way (hover is *lighter*, the soft\n * tint is a dark shade, and readable text on that tint is a light shade) — the\n * same inversion the built-in `colors.css` dark block does by hand.\n *\n * The selected-state indicator is derived from the same measurement as the focus\n * ring and emitted as its own token. It never takes `focusRingAlpha`: a\n * translucent ring over a known background is a legitimate choice a theme can\n * make, while a translucent *state* indicator has the contrast of whatever it\n * composites over, which is the defect this token exists to end.\n *\n * @param tokens - The token map for this scheme, written in place.\n * @param scale - The generated primary ramp.\n * @param scheme - Which scheme is being emitted.\n * @param surfaces - The surfaces this theme paints, for the focus-ring measurement.\n * @param focusRingAlpha - Opacity asked for the ring, or `undefined` for opaque.\n */\nfunction writePrimaryAliases(\n tokens: Record<string, string>,\n scale: ColorScale,\n scheme: \"light\" | \"dark\",\n surfaces: readonly string[],\n focusRingAlpha: number | undefined,\n): void {\n tokens[\"--tempest-primary\"] = \"var(--tempest-primary-500)\";\n if (scheme === \"light\") {\n tokens[\"--tempest-primary-hover\"] = \"var(--tempest-primary-600)\";\n tokens[\"--tempest-primary-active\"] = \"var(--tempest-primary-700)\";\n tokens[\"--tempest-primary-soft\"] = \"var(--tempest-primary-50)\";\n tokens[\"--tempest-primary-soft-hover\"] = \"var(--tempest-primary-100)\";\n tokens[\"--tempest-primary-on-soft\"] =\n `var(--tempest-primary-${pickOnSoftStep(scale, 50, [600, 700, 800, 900])})`;\n } else {\n tokens[\"--tempest-primary-hover\"] = \"var(--tempest-primary-400)\";\n tokens[\"--tempest-primary-active\"] = \"var(--tempest-primary-300)\";\n tokens[\"--tempest-primary-soft\"] = \"var(--tempest-primary-100)\";\n tokens[\"--tempest-primary-soft-hover\"] = \"var(--tempest-primary-200)\";\n tokens[\"--tempest-primary-on-soft\"] =\n `var(--tempest-primary-${pickOnSoftStep(scale, 100, [700, 800, 900])})`;\n }\n\n const foreground = readableForeground(scale[500]);\n tokens[\"--tempest-primary-foreground\"] = foreground;\n tokens[\"--tempest-text-on-primary\"] = foreground;\n const ring = scale[pickFocusRingStep(scale, surfaces)];\n tokens[\"--tempest-focus-ring-color\"] =\n focusRingAlpha === undefined || focusRingAlpha >= 1\n ? ring\n : hexToRgbaString(ring, focusRingAlpha);\n tokens[\"--tempest-selected-indicator\"] = ring;\n}\n\n/**\n * Emit the neutral surface/border/text aliases from a generated gray scale.\n *\n * `--tempest-bg` is pushed past the ramp on purpose: pure white in light mode and\n * a shade darker than `gray-50` in dark mode, so a raised surface still reads as\n * raised against the page.\n */\nfunction writeNeutralAliases(\n tokens: Record<string, string>,\n scale: ColorScale,\n scheme: \"light\" | \"dark\",\n): void {\n if (scheme === \"light\") {\n tokens[\"--tempest-bg\"] = \"#ffffff\";\n tokens[\"--tempest-surface\"] = \"var(--tempest-gray-50)\";\n tokens[\"--tempest-surface-2\"] = \"var(--tempest-gray-100)\";\n tokens[\"--tempest-surface-3\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-border\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-border-strong\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-text\"] = \"var(--tempest-gray-900)\";\n tokens[\"--tempest-text-muted\"] = \"var(--tempest-gray-600)\";\n tokens[\"--tempest-text-subtle\"] = \"var(--tempest-gray-500)\";\n } else {\n tokens[\"--tempest-bg\"] = scale[50];\n tokens[\"--tempest-surface\"] = \"var(--tempest-gray-100)\";\n tokens[\"--tempest-surface-2\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-surface-3\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-border\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-border-strong\"] = \"var(--tempest-gray-400)\";\n tokens[\"--tempest-text\"] = \"var(--tempest-gray-900)\";\n tokens[\"--tempest-text-muted\"] = \"var(--tempest-gray-700)\";\n tokens[\"--tempest-text-subtle\"] = \"var(--tempest-gray-600)\";\n }\n tokens[\"--tempest-neutral-on-solid\"] = readableForeground(scale[700], \"#ffffff\", ON_SOLID_INK);\n}\n\nfunction renderBlock(selector: string, tokens: Record<string, string>): string {\n const entries = Object.entries(tokens);\n if (entries.length === 0) return \"\";\n const body = entries.map(([name, value]) => ` ${name}: ${value};`).join(\"\\n\");\n return `${selector} {\\n${body}\\n}`;\n}\n\n/**\n * Generate `--tempest-*` overrides from a small brand description.\n *\n * Only the families you pass are generated; everything else falls through to the\n * SDK's own tokens, so a theme stays a patch and not a fork of `colors.css`.\n *\n * @example\n * ```ts\n * import { applyTheme, createTheme } from \"tempest-react-sdk\";\n *\n * const theme = createTheme({\n * primary: \"#7c3aed\",\n * radius: \"lg\",\n * chart: [\"#7c3aed\", \"#0ea5e9\", \"#22c55e\", \"#f59e0b\"],\n * });\n *\n * applyTheme(theme);\n * ```\n *\n * @param options - Brand colors plus optional radius / chart / focus-ring tuning.\n * @returns The light and dark token maps and the CSS text that carries them.\n */\nexport function createTheme(options: CreateThemeOptions = {}): GeneratedTheme {\n const {\n primary,\n gray,\n chart,\n radius,\n focusRingAlpha,\n selector = \":root\",\n darkSelector = '[data-tempest-theme=\"dark\"]',\n inverse,\n inverseSelector = INVERSE_SELECTOR,\n } = options;\n\n warnOnTranslucentFocusRing(focusRingAlpha);\n\n const light: Record<string, string> = {};\n const dark: Record<string, string> = {};\n\n // `anchor: false`: a neutral ramp has to keep its tuned lightness curve.\n // Anchoring it at the input compressed both halves and dropped\n // text-muted-on-surface-3 to ~4.2:1 — below AA — which the browser axe\n // sweep caught on the generated themes.\n const grayScales = gray\n ? {\n light: createColorScale(gray, \"light\", { anchor: false, neutral: true }),\n dark: createColorScale(gray, \"dark\", { anchor: false, neutral: true }),\n }\n : undefined;\n\n if (primary) {\n const lightScale = createColorScale(primary, \"light\");\n const darkScale = createColorScale(primary, \"dark\");\n writeScale(light, \"primary\", lightScale);\n writeScale(dark, \"primary\", darkScale);\n writePrimaryAliases(\n light,\n lightScale,\n \"light\",\n surfacesOf(\"light\", grayScales),\n focusRingAlpha,\n );\n writePrimaryAliases(\n dark,\n darkScale,\n \"dark\",\n surfacesOf(\"dark\", grayScales),\n focusRingAlpha,\n );\n }\n\n if (grayScales) {\n writeScale(light, \"gray\", grayScales.light);\n writeScale(dark, \"gray\", grayScales.dark);\n writeNeutralAliases(light, grayScales.light, \"light\");\n writeNeutralAliases(dark, grayScales.dark, \"dark\");\n }\n\n for (const status of THEME_STATUSES) {\n const value = options[status];\n if (!value) continue;\n writeStatus(light, status, createColorScale(value, \"light\"), \"light\");\n writeStatus(dark, status, createColorScale(value, \"dark\"), \"dark\");\n }\n\n if (chart?.length) {\n chart.forEach((color, index) => {\n light[`--tempest-chart-${index + 1}`] = color;\n });\n // Declares how many series colors this theme owns. Without it the reader\n // keeps walking into the SDK's built-in `--tempest-chart-7`/`-8`, so a\n // 6-color brand palette silently mixes with two leftover defaults — which\n // is exactly what a 7-series chart would show.\n light[\"--tempest-chart-count\"] = String(chart.length);\n }\n\n /*\n * Continuous scales follow the brand too.\n *\n * Without this a rebranded app gets its categorical slots recoloured and then a\n * heatmap still painted in the SDK's blue — the one chart on the page that\n * silently ignores the brand. Both scales derive from the first series hue (or\n * the primary), stepped by perceptual lightness for each mode separately.\n *\n * Skipped entirely when the theme names no colour to derive from, so the\n * built-in tokens survive instead of being overwritten with a guess.\n */\n const scaleSource = chart?.[0] ?? primary;\n if (scaleSource) {\n const coolHue = hueOf(scaleSource);\n // The opposite pole: the brand's own danger colour when it has one, since a\n // diverging scale's warm arm and \"bad\" should not disagree on screen.\n const warmHue = options.danger ? hueOf(options.danger) : (coolHue + 180) % 360;\n for (const [target, mode] of [\n [light, \"light\"],\n [dark, \"dark\"],\n ] as const) {\n buildRamp(coolHue, mode).forEach((stepColor, index) => {\n target[`--tempest-chart-sequential-${index + 1}`] = stepColor;\n });\n const diverging = buildDivergingRamp({\n coolHue,\n warmHue,\n mid: mode === \"light\" ? \"#e4e7ec\" : \"#262d3f\",\n mode,\n });\n [...diverging.cool, diverging.mid, ...diverging.warm].forEach((stepColor, index) => {\n target[`--tempest-chart-diverging-${index + 1}`] = stepColor;\n });\n }\n }\n\n if (radius) {\n const steps = typeof radius === \"string\" ? RADIUS_PRESETS[radius] : radius;\n for (const [step, value] of Object.entries(steps)) {\n light[`--tempest-radius-${step}`] = value;\n }\n }\n\n const inverseSurface =\n primary && inverse\n ? inverse({\n primary,\n statuses: {\n success: options.success,\n warning: options.warning,\n danger: options.danger,\n info: options.info,\n },\n chart,\n selector: inverseSelector,\n page: { selector, darkSelector },\n })\n : null;\n\n const css = [\n renderBlock(selector, light),\n renderBlock(darkSelector, dark),\n inverseSurface ? renderInverseSurface(inverseSelector, inverseSurface) : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n return inverseSurface\n ? { light, dark, inverse: inverseSurface.tokens, css }\n : { light, dark, css };\n}\n\n/**\n * Contrast ratio of `--tempest-primary-foreground` over the brand color.\n *\n * Exposed so an app (or a test) can assert its own brand clears WCAG AA (4.5) for\n * body text or AA-large (3.0) for button labels, instead of trusting the pick.\n *\n * @param options - The same input given to {@link createTheme}.\n * @returns The ratio, or `null` when no `primary` was provided.\n */\nexport function themeContrast(options: CreateThemeOptions): number | null {\n if (!options.primary) return null;\n const scale = createColorScale(options.primary, \"light\");\n return contrastRatio(scale[500], readableForeground(scale[500]));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"create-theme.js","names":["RADIUS_PRESETS","SCALE_STEPS","writeScale","step","name","scale","AA_TEXT_CONTRAST","pickOnSoftStep","candidates","contrastRatio","softStep","INDICATOR_CONTRAST","SDK_SURFACES","FOCUS_RING_CANDIDATES","pickFocusRingStep","worstCase","surfaces","surface","best","bestRatio","measured","surfacesOf","grayScales","scheme","warnOnTranslucentFocusRing","focusRingAlpha","isDevBuild","writePrimaryAliases","foreground","readableForeground","ring","hexToRgbaString","writeNeutralAliases","ON_SOLID_INK","renderBlock","entries","tokens","selector","value","createTheme","INVERSE_SELECTOR","options","light","dark","gray","createColorScale","primary","lightScale","darkScale","status","THEME_STATUSES","writeStatus","chart","index","color","scaleSource","coolHue","hueOf","warmHue","target","mode","stepColor","diverging","buildDivergingRamp","radius","steps","inverseSurface","inverse","inverseSelector","css","darkSelector","renderInverseSurface","themeContrast"],"sources":["../../src/theme/create-theme.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — one pass that emits the whole token set — surfaces,\n * text, borders, states, the chart ramps — for both modes, with every value checked\n * against the surface it will sit on. The checks are what make the length: each\n * token is derived and then verified against the same background table.\n */\n/**\n * Theme factory: turns a handful of brand colors into the full set of\n * `--tempest-*` token overrides, for both light and dark.\n *\n * Rebranding used to mean hand-writing ~167 custom properties (and getting the\n * dark ramp inversion right by hand). `createTheme({ primary: \"#7c3aed\" })`\n * emits the same thing, derived in OKLCH so the ramp stays perceptually even.\n */\nimport {\n contrastRatio,\n createColorScale,\n hexToRgbaString,\n readableForeground,\n type ColorScale,\n type ScaleStep,\n} from \"./color\";\nimport { buildDivergingRamp, buildRamp, hueOf } from \"./data-viz-ramps\";\nimport { isDevBuild } from \"../utils/dev-mode\";\nimport {\n INVERSE_SELECTOR,\n renderInverseSurface,\n type InverseSurfaceGenerator,\n} from \"./inverse-render\";\nimport { ON_SOLID_INK, THEME_STATUSES, writeStatus } from \"./status-tokens\";\n\n/** Radius presets, applied to the whole `--tempest-radius-*` family at once. */\nexport type ThemeRadius = \"none\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\";\n\nexport type { ThemeStatus } from \"./status-tokens\";\n\n/** Input for {@link createTheme}. Every field is optional — omitted families keep the built-in tokens. */\nexport interface CreateThemeOptions {\n /** Brand color, used as the `500` step of the primary scale. */\n primary?: string;\n /** Neutral color, used as the `500` step of the gray scale (surfaces, borders, text). */\n gray?: string;\n /** Success color (`--tempest-success*`). */\n success?: string;\n /** Warning color (`--tempest-warning*`). */\n warning?: string;\n /** Danger color (`--tempest-danger*`). */\n danger?: string;\n /** Info color (`--tempest-info*`). */\n info?: string;\n /**\n * Categorical series colors for `tempest-react-sdk/charts`, in cycle order.\n * Written to `--tempest-chart-1` … `--tempest-chart-N`, so charts follow the\n * theme instead of a hardcoded palette.\n */\n chart?: string[];\n /** Corner radius scale. A preset name, or explicit per-step values. */\n radius?: ThemeRadius | Partial<Record<\"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\", string>>;\n /**\n * Opacity of `--tempest-focus-ring-color`. Omit it — the default ring is opaque.\n *\n * A translucent ring has no contrast of its own; it has the contrast of\n * whatever it composites over. Passing a value below `1` reintroduces the\n * failure 0.61.0 fixed in the built-in tokens, and logs a warning in a\n * development build. Kept because a translucent ring over a background you\n * control is a legitimate choice.\n */\n focusRingAlpha?: number;\n /** Selector the light tokens are written under. Default `\":root\"`. */\n selector?: string;\n /** Selector the dark tokens are written under. Default `'[data-tempest-theme=\"dark\"]'`. */\n darkSelector?: string;\n /**\n * Also emit the inverse surface — the token set for a section painted in the\n * brand color — by passing its generator, `createInverseSurface`. Off by\n * default; ignored without `primary`.\n *\n * The generator is passed in rather than switched on with `true` so that\n * `createTheme` never imports it: an app that does not paint a section in\n * its brand does not ship the 1.68 kB brotli it costs.\n *\n * @example\n * ```ts\n * import { createInverseSurface, createTheme } from \"tempest-react-sdk\";\n *\n * createTheme({ primary: \"#03184b\", inverse: createInverseSurface });\n * ```\n */\n inverse?: InverseSurfaceGenerator;\n /** Selector the inverse tokens are written under. Default `'[data-tempest-tone=\"inverse\"]'`. */\n inverseSelector?: string;\n}\n\n/** A generated theme: token maps per color scheme, plus the CSS text that carries them. */\nexport interface GeneratedTheme {\n /** Light-scheme custom properties, without the leading `--`-less names (keys include `--`). */\n light: Record<string, string>;\n /** Dark-scheme custom properties. */\n dark: Record<string, string>;\n /**\n * Inverse-surface custom properties — literal colors, identical under the\n * light and the dark page scheme. Present only when the theme names a\n * `primary` and passes `inverse`.\n */\n inverse?: Record<string, string>;\n /** Both blocks rendered as CSS, ready for {@link applyTheme} or a stylesheet. */\n css: string;\n}\n\nconst RADIUS_PRESETS: Record<ThemeRadius, Record<string, string>> = {\n none: { xs: \"0\", sm: \"0\", md: \"0\", lg: \"0\", xl: \"0\", \"2xl\": \"0\" },\n sm: { xs: \"1px\", sm: \"2px\", md: \"4px\", lg: \"6px\", xl: \"8px\", \"2xl\": \"12px\" },\n md: { xs: \"2px\", sm: \"4px\", md: \"8px\", lg: \"12px\", xl: \"16px\", \"2xl\": \"24px\" },\n lg: { xs: \"4px\", sm: \"6px\", md: \"12px\", lg: \"16px\", xl: \"22px\", \"2xl\": \"32px\" },\n xl: { xs: \"6px\", sm: \"10px\", md: \"16px\", lg: \"24px\", xl: \"32px\", \"2xl\": \"44px\" },\n full: { xs: \"4px\", sm: \"8px\", md: \"9999px\", lg: \"9999px\", xl: \"9999px\", \"2xl\": \"9999px\" },\n};\n\nconst SCALE_STEPS: ScaleStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\n\nfunction writeScale(tokens: Record<string, string>, name: string, scale: ColorScale): void {\n for (const step of SCALE_STEPS) {\n tokens[`--tempest-${name}-${step}`] = scale[step];\n }\n}\n\n/** Minimum contrast for body text, WCAG 2.x AA. */\nconst AA_TEXT_CONTRAST = 4.5;\n\n/**\n * Choose the ramp step for text sitting on the soft tint.\n *\n * A fixed step does not survive an arbitrary brand color: the built-in blue only\n * reaches 4.37:1 at `500` over its own `50` tint, and a generated emerald lands\n * at 4.41:1 at `600` — both fail AA for body text by a hair. So the step is\n * picked by measuring, walking away from the tint until it clears AA, and\n * falling back to the most extreme candidate when even that cannot (a very light\n * or very desaturated brand).\n *\n * @param scale - The generated ramp.\n * @param softStep - Step used as `--tempest-primary-soft`.\n * @param candidates - Steps to try, in order of preference.\n * @returns The first candidate clearing {@link AA_TEXT_CONTRAST}, else the last.\n */\nfunction pickOnSoftStep(\n scale: ColorScale,\n softStep: ScaleStep,\n candidates: ScaleStep[],\n): ScaleStep {\n for (const step of candidates) {\n if (contrastRatio(scale[softStep], scale[step]) >= AA_TEXT_CONTRAST) return step;\n }\n return candidates[candidates.length - 1];\n}\n\n/** Minimum contrast for a non-text indicator, WCAG 2.2 SC 1.4.11. */\nconst INDICATOR_CONTRAST = 3;\n\n/**\n * The four surfaces a focus ring can land on, as the SDK's own `colors.css`\n * paints them.\n *\n * Ported from `src/styles/colors.css` (`--tempest-bg`, `--tempest-surface`,\n * `--tempest-surface-2`, `--tempest-surface-3`, resolved through the gray ramp),\n * and pinned by a test that reads that file — a theme that only names `primary`\n * keeps these, so the ring has to be measured against them and not against a\n * guess. The light values resolve through `--tempest-gray-50/100/200`; the dark\n * ones are literals in the dark block.\n */\nconst SDK_SURFACES: Record<\"light\" | \"dark\", readonly string[]> = {\n light: [\"#ffffff\", \"#f8f9fb\", \"#f1f3f6\", \"#e4e7ec\"],\n dark: [\"#0b0d12\", \"#14171f\", \"#1d2230\", \"#262d3f\"],\n};\n\n/**\n * Ramp steps to try for the focus ring, in order.\n *\n * `500` first, because the ring should read as the brand when it can, then up\n * the ramp — which moves away from the surfaces in **both** schemes, because\n * `createColorScale` inverts the dark ramp: there `50` is the darkest step (it\n * is what `--tempest-bg` is made of) and `900` the lightest. Walking down in\n * dark mode looks like the right inversion and is the wrong direction; measured,\n * it left a near-black brand's ring at 1.04:1 over its own background.\n */\nconst FOCUS_RING_CANDIDATES: readonly ScaleStep[] = [500, 600, 700, 800, 900];\n\n/**\n * Choose the ramp step for the focus ring, by measuring it against the surfaces\n * it will actually be drawn on.\n *\n * A fixed step does not survive an arbitrary brand, and the measurement says so\n * loudly: of twelve brands checked against the four surfaces in both schemes —\n * 96 pairings — `500` opaque clears 3:1 in 58 of them, and `500` at the old\n * default alpha of 0.35 in 3. Picking the step by measurement clears all 96. The\n * brand from the report that opened this\n * (`#8100D7`) passes in light at 7.20:1 and fails in **dark** at 2.70:1 down to\n * 1.91:1 on `surface-3`; a yellow fails in light at 1.43:1. So the step is\n * picked the way {@link pickOnSoftStep} picks text on a tint: walk away from the\n * surfaces until the ring clears the floor against *all* of them.\n *\n * The fallback is the candidate with the best worst case rather than the last\n * one, because \"the most extreme step\" is not always the most contrasting one\n * once a brand is near-neutral.\n *\n * @param scale - The generated ramp.\n * @param surfaces - The four surfaces this theme will paint, opaque hex.\n * @returns The first candidate clearing {@link INDICATOR_CONTRAST} on every\n * surface, else the candidate whose weakest pairing is strongest.\n */\nfunction pickFocusRingStep(scale: ColorScale, surfaces: readonly string[]): ScaleStep {\n const worstCase = (step: ScaleStep): number =>\n Math.min(...surfaces.map((surface) => contrastRatio(scale[step], surface)));\n let best: ScaleStep = FOCUS_RING_CANDIDATES[0] as ScaleStep;\n let bestRatio = -1;\n for (const step of FOCUS_RING_CANDIDATES) {\n const measured = worstCase(step);\n if (measured >= INDICATOR_CONTRAST) return step;\n if (measured > bestRatio) {\n best = step;\n bestRatio = measured;\n }\n }\n return best;\n}\n\n/**\n * The surfaces this theme will actually paint, per scheme.\n *\n * A theme that names `gray` repaints all four, so measuring the ring against the\n * SDK's would be measuring the wrong backdrop — and a theme that does not keeps\n * the SDK's, which is the common case. The order and the ramp steps mirror\n * {@link writeNeutralAliases}, which is what emits them.\n *\n * @param scheme - Which scheme is being emitted.\n * @param grayScales - The generated neutral ramps, when the theme names one.\n * @returns Four opaque hex colors: bg, surface, surface-2, surface-3.\n */\nfunction surfacesOf(\n scheme: \"light\" | \"dark\",\n grayScales: { light: ColorScale; dark: ColorScale } | undefined,\n): readonly string[] {\n if (!grayScales) return SDK_SURFACES[scheme];\n const scale = grayScales[scheme];\n return scheme === \"light\"\n ? [\"#ffffff\", scale[50], scale[100], scale[200]]\n : [scale[50], scale[100], scale[200], scale[300]];\n}\n\n/**\n * Warn, in a development build, that an alpha was asked for the focus ring.\n *\n * A translucent ring has no contrast of its own — it has the contrast of\n * whatever it composites over — and that is the failure this option used to\n * ship by default: measured at alpha `0.35`, twelve brands across four surfaces\n * and both schemes produced 96 pairings, of which 3 cleared the 3:1 of WCAG 2.2\n * SC 1.4.11. It stays available, because a translucent ring over a\n * known background is a legitimate choice, but it is a choice a theme now has to\n * make on purpose.\n *\n * The warning is the difficult part to notice otherwise: a failing focus ring is\n * visible, it just does not separate.\n *\n * @param focusRingAlpha - The opacity the caller asked for, if any.\n */\nfunction warnOnTranslucentFocusRing(focusRingAlpha: number | undefined): void {\n if (focusRingAlpha === undefined || focusRingAlpha >= 1) return;\n if (!isDevBuild()) return;\n console.warn(\n `[tempest-react-sdk] createTheme({ focusRingAlpha: ${focusRingAlpha} }) makes the focus ring ` +\n \"translucent, so its contrast becomes whatever it composites over — measured below the 3:1 \" +\n \"of WCAG 2.2 SC 1.4.11 on every surface the SDK paints. Drop the option to get the opaque \" +\n \"ring, which is derived from your brand ramp and measured against those surfaces.\",\n );\n}\n\n/**\n * Emit the primary aliases for one scheme.\n *\n * The dark scheme walks the ramp the other way (hover is *lighter*, the soft\n * tint is a dark shade, and readable text on that tint is a light shade) — the\n * same inversion the built-in `colors.css` dark block does by hand.\n *\n * The selected-state indicator is derived from the same measurement as the focus\n * ring and emitted as its own token. It never takes `focusRingAlpha`: a\n * translucent ring over a known background is a legitimate choice a theme can\n * make, while a translucent *state* indicator has the contrast of whatever it\n * composites over, which is the defect this token exists to end.\n *\n * @param tokens - The token map for this scheme, written in place.\n * @param scale - The generated primary ramp.\n * @param scheme - Which scheme is being emitted.\n * @param surfaces - The surfaces this theme paints, for the focus-ring measurement.\n * @param focusRingAlpha - Opacity asked for the ring, or `undefined` for opaque.\n */\nfunction writePrimaryAliases(\n tokens: Record<string, string>,\n scale: ColorScale,\n scheme: \"light\" | \"dark\",\n surfaces: readonly string[],\n focusRingAlpha: number | undefined,\n): void {\n tokens[\"--tempest-primary\"] = \"var(--tempest-primary-500)\";\n if (scheme === \"light\") {\n tokens[\"--tempest-primary-hover\"] = \"var(--tempest-primary-600)\";\n tokens[\"--tempest-primary-active\"] = \"var(--tempest-primary-700)\";\n tokens[\"--tempest-primary-soft\"] = \"var(--tempest-primary-50)\";\n tokens[\"--tempest-primary-soft-hover\"] = \"var(--tempest-primary-100)\";\n tokens[\"--tempest-primary-on-soft\"] =\n `var(--tempest-primary-${pickOnSoftStep(scale, 50, [600, 700, 800, 900])})`;\n } else {\n tokens[\"--tempest-primary-hover\"] = \"var(--tempest-primary-400)\";\n tokens[\"--tempest-primary-active\"] = \"var(--tempest-primary-300)\";\n tokens[\"--tempest-primary-soft\"] = \"var(--tempest-primary-100)\";\n tokens[\"--tempest-primary-soft-hover\"] = \"var(--tempest-primary-200)\";\n tokens[\"--tempest-primary-on-soft\"] =\n `var(--tempest-primary-${pickOnSoftStep(scale, 100, [700, 800, 900])})`;\n }\n\n const foreground = readableForeground(scale[500]);\n tokens[\"--tempest-primary-foreground\"] = foreground;\n tokens[\"--tempest-text-on-primary\"] = foreground;\n const ring = scale[pickFocusRingStep(scale, surfaces)];\n tokens[\"--tempest-focus-ring-color\"] =\n focusRingAlpha === undefined || focusRingAlpha >= 1\n ? ring\n : hexToRgbaString(ring, focusRingAlpha);\n tokens[\"--tempest-selected-indicator\"] = ring;\n}\n\n/**\n * Emit the neutral surface/border/text aliases from a generated gray scale.\n *\n * `--tempest-bg` is pushed past the ramp on purpose: pure white in light mode and\n * a shade darker than `gray-50` in dark mode, so a raised surface still reads as\n * raised against the page.\n */\nfunction writeNeutralAliases(\n tokens: Record<string, string>,\n scale: ColorScale,\n scheme: \"light\" | \"dark\",\n): void {\n if (scheme === \"light\") {\n tokens[\"--tempest-bg\"] = \"#ffffff\";\n tokens[\"--tempest-surface\"] = \"var(--tempest-gray-50)\";\n tokens[\"--tempest-surface-2\"] = \"var(--tempest-gray-100)\";\n tokens[\"--tempest-surface-3\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-border\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-border-strong\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-text\"] = \"var(--tempest-gray-900)\";\n tokens[\"--tempest-text-muted\"] = \"var(--tempest-gray-600)\";\n tokens[\"--tempest-text-subtle\"] = \"var(--tempest-gray-500)\";\n } else {\n tokens[\"--tempest-bg\"] = scale[50];\n tokens[\"--tempest-surface\"] = \"var(--tempest-gray-100)\";\n tokens[\"--tempest-surface-2\"] = \"var(--tempest-gray-200)\";\n tokens[\"--tempest-surface-3\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-border\"] = \"var(--tempest-gray-300)\";\n tokens[\"--tempest-border-strong\"] = \"var(--tempest-gray-400)\";\n tokens[\"--tempest-text\"] = \"var(--tempest-gray-900)\";\n tokens[\"--tempest-text-muted\"] = \"var(--tempest-gray-700)\";\n tokens[\"--tempest-text-subtle\"] = \"var(--tempest-gray-600)\";\n }\n tokens[\"--tempest-neutral-on-solid\"] = readableForeground(scale[700], \"#ffffff\", ON_SOLID_INK);\n}\n\nfunction renderBlock(selector: string, tokens: Record<string, string>): string {\n const entries = Object.entries(tokens);\n if (entries.length === 0) return \"\";\n const body = entries.map(([name, value]) => ` ${name}: ${value};`).join(\"\\n\");\n return `${selector} {\\n${body}\\n}`;\n}\n\n/**\n * Generate `--tempest-*` overrides from a small brand description.\n *\n * Only the families you pass are generated; everything else falls through to the\n * SDK's own tokens, so a theme stays a patch and not a fork of `colors.css`.\n *\n * @example\n * ```ts\n * import { applyTheme, createTheme } from \"tempest-react-sdk\";\n *\n * const theme = createTheme({\n * primary: \"#7c3aed\",\n * radius: \"lg\",\n * chart: [\"#7c3aed\", \"#0ea5e9\", \"#22c55e\", \"#f59e0b\"],\n * });\n *\n * applyTheme(theme);\n * ```\n *\n * @param options - Brand colors plus optional radius / chart / focus-ring tuning.\n * @returns The light and dark token maps and the CSS text that carries them.\n */\nexport function createTheme(options: CreateThemeOptions = {}): GeneratedTheme {\n const {\n primary,\n gray,\n chart,\n radius,\n focusRingAlpha,\n selector = \":root\",\n darkSelector = '[data-tempest-theme=\"dark\"]',\n inverse,\n inverseSelector = INVERSE_SELECTOR,\n } = options;\n\n warnOnTranslucentFocusRing(focusRingAlpha);\n\n const light: Record<string, string> = {};\n const dark: Record<string, string> = {};\n\n // `anchor: false`: a neutral ramp has to keep its tuned lightness curve.\n // Anchoring it at the input compressed both halves and dropped\n // text-muted-on-surface-3 to ~4.2:1 — below AA — which the browser axe\n // sweep caught on the generated themes.\n const grayScales = gray\n ? {\n light: createColorScale(gray, \"light\", { anchor: false, neutral: true }),\n dark: createColorScale(gray, \"dark\", { anchor: false, neutral: true }),\n }\n : undefined;\n\n if (primary) {\n const lightScale = createColorScale(primary, \"light\");\n const darkScale = createColorScale(primary, \"dark\");\n writeScale(light, \"primary\", lightScale);\n writeScale(dark, \"primary\", darkScale);\n writePrimaryAliases(\n light,\n lightScale,\n \"light\",\n surfacesOf(\"light\", grayScales),\n focusRingAlpha,\n );\n writePrimaryAliases(\n dark,\n darkScale,\n \"dark\",\n surfacesOf(\"dark\", grayScales),\n focusRingAlpha,\n );\n }\n\n if (grayScales) {\n writeScale(light, \"gray\", grayScales.light);\n writeScale(dark, \"gray\", grayScales.dark);\n writeNeutralAliases(light, grayScales.light, \"light\");\n writeNeutralAliases(dark, grayScales.dark, \"dark\");\n }\n\n for (const status of THEME_STATUSES) {\n const value = options[status];\n if (!value) continue;\n writeStatus(light, status, createColorScale(value, \"light\"), \"light\");\n writeStatus(dark, status, createColorScale(value, \"dark\"), \"dark\");\n }\n\n if (chart?.length) {\n chart.forEach((color, index) => {\n light[`--tempest-chart-${index + 1}`] = color;\n });\n // Declares how many series colors this theme owns. Without it the reader\n // keeps walking into the SDK's built-in `--tempest-chart-7`/`-8`, so a\n // 6-color brand palette silently mixes with two leftover defaults — which\n // is exactly what a 7-series chart would show.\n light[\"--tempest-chart-count\"] = String(chart.length);\n }\n\n /*\n * Continuous scales follow the brand too.\n *\n * Without this a rebranded app gets its categorical slots recoloured and then a\n * heatmap still painted in the SDK's blue — the one chart on the page that\n * silently ignores the brand. Both scales derive from the first series hue (or\n * the primary), stepped by perceptual lightness for each mode separately.\n *\n * Skipped entirely when the theme names no colour to derive from, so the\n * built-in tokens survive instead of being overwritten with a guess.\n */\n const scaleSource = chart?.[0] ?? primary;\n if (scaleSource) {\n const coolHue = hueOf(scaleSource);\n // The opposite pole: the brand's own danger colour when it has one, since a\n // diverging scale's warm arm and \"bad\" should not disagree on screen.\n const warmHue = options.danger ? hueOf(options.danger) : (coolHue + 180) % 360;\n for (const [target, mode] of [\n [light, \"light\"],\n [dark, \"dark\"],\n ] as const) {\n buildRamp(coolHue, mode).forEach((stepColor, index) => {\n target[`--tempest-chart-sequential-${index + 1}`] = stepColor;\n });\n const diverging = buildDivergingRamp({\n coolHue,\n warmHue,\n mid: mode === \"light\" ? \"#e4e7ec\" : \"#262d3f\",\n mode,\n });\n [...diverging.cool, diverging.mid, ...diverging.warm].forEach((stepColor, index) => {\n target[`--tempest-chart-diverging-${index + 1}`] = stepColor;\n });\n }\n }\n\n if (radius) {\n const steps = typeof radius === \"string\" ? RADIUS_PRESETS[radius] : radius;\n for (const [step, value] of Object.entries(steps)) {\n light[`--tempest-radius-${step}`] = value;\n }\n }\n\n const inverseSurface =\n primary && inverse\n ? inverse({\n primary,\n statuses: {\n success: options.success,\n warning: options.warning,\n danger: options.danger,\n info: options.info,\n },\n chart,\n selector: inverseSelector,\n page: { selector, darkSelector },\n })\n : null;\n\n const css = [\n renderBlock(selector, light),\n renderBlock(darkSelector, dark),\n inverseSurface ? renderInverseSurface(inverseSelector, inverseSurface) : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n return inverseSurface\n ? { light, dark, inverse: inverseSurface.tokens, css }\n : { light, dark, css };\n}\n\n/**\n * Contrast ratio of `--tempest-primary-foreground` over the brand color.\n *\n * Exposed so an app (or a test) can assert its own brand clears WCAG AA (4.5) for\n * body text or AA-large (3.0) for button labels, instead of trusting the pick.\n *\n * @param options - The same input given to {@link createTheme}.\n * @returns The ratio, or `null` when no `primary` was provided.\n */\nexport function themeContrast(options: CreateThemeOptions): number | null {\n if (!options.primary) return null;\n const scale = createColorScale(options.primary, \"light\");\n return contrastRatio(scale[500], readableForeground(scale[500]));\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"data-viz-ramps.cjs","names":[],"sources":["../../src/theme/data-viz-ramps.ts"],"sourcesContent":["import { contrastRatio, hexToOklch, oklchToHex } from \"./color\";\n\n/** Number of steps in a sequential ramp. */\nexport const SEQUENTIAL_STEPS = 7;\n\n/** Steps per arm of a diverging scale, excluding the neutral midpoint. */\nexport const DIVERGING_ARM_STEPS = 4;\n\n/** A diverging scale: cool arm (extreme → near-mid), the midpoint, then the warm arm. */\nexport interface DivergingRamp {\n cool: string[];\n mid: string;\n warm: string[];\n}\n\n/**\n * Lightness range a ramp spans, per mode.\n *\n * Dark mode is **selected, not flipped**: its own band, chosen for the dark surface.\n * Mechanically inverting the light ramp yields steps that are either invisible\n * against a near-black surface or so bright they read as highlights.\n */\nconst BAND = {\n light: { from: 0.93, to: 0.34 },\n dark: { from: 0.28, to: 0.86 },\n} as const;\n\n/**\n * Chroma shaped as a dome across the ramp.\n *\n * A constant chroma makes the pale end look muddy and the dark end look neon. The\n * dome keeps the extremes believable while the middle carries the hue, which is\n * what makes a heatmap readable at a glance.\n *\n * @param t - Position along the ramp, `0`–`1`.\n * @returns A multiplier for the peak chroma.\n */\nfunction chromaDome(t: number): number {\n return 0.35 + 0.65 * (1 - Math.abs(2 * t - 1) ** 1.6);\n}\n\nexport interface BuildRampOptions {\n /** How many steps to emit. Defaults to {@link SEQUENTIAL_STEPS}. */\n steps?: number;\n /** Chroma at the middle of the ramp. */\n peakChroma?: number;\n}\n\n/**\n * Build a single-hue ramp with evenly spaced perceptual lightness.\n *\n * Even spacing in OKLCH lightness — not in RGB — is what makes equal data steps look\n * like equal colour steps.\n *\n * Steps come back in **token order**: index 0 is the end that means \"near zero\", so\n * it is the lightest on a light canvas and the darkest on a dark one. That is the\n * order `--tempest-chart-sequential-1…7` is written in, and it makes index 0 the step\n * nearest the surface in both modes — which is what `ordinalStart` walks from.\n * Returning a fixed light→dark order instead would put token 1 at opposite ends of\n * the scale depending on the mode, and a dark theme would paint every heatmap\n * inverted.\n *\n * @param hue - OKLCH hue in degrees.\n * @param mode - Which lightness band to span.\n * @param options - Shape of the ramp: `steps` (how many to emit) and `peakChroma`\n * (chroma at the middle).\n * @returns Hex steps, near-zero end first.\n */\nexport function buildRamp(\n hue: number,\n mode: \"light\" | \"dark\",\n { steps = SEQUENTIAL_STEPS, peakChroma = 0.19 }: BuildRampOptions = {},\n): string[] {\n const band = BAND[mode];\n const out: string[] = [];\n for (let i = 0; i < steps; i += 1) {\n const t = steps === 1 ? 0 : i / (steps - 1);\n out.push(\n oklchToHex({\n l: band.from + (band.to - band.from) * t,\n c: peakChroma * chromaDome(t),\n h: hue,\n }),\n );\n }\n return out;\n}\n\n/**\n * The first index of `ramp` that clears `minContrast` against `surface`.\n *\n * A **sequential** ramp may let its near-zero end recede into the surface — that is\n * what \"almost nothing\" should look like on a heatmap. An **ordinal** ramp may not:\n * every step is a discrete mark a reader has to see. This is how a consumer finds\n * where the ordinal-safe slice of a sequential ramp begins.\n *\n * @param ramp - Hex steps in token order, near-zero end first.\n * @param surface - The chart surface the ramp sits on.\n * @param minContrast - Floor to clear. Default `2` — the ordinal floor.\n * @returns The first safe index, or `0` when every step already clears it.\n */\nexport function ordinalStart(ramp: string[], surface: string, minContrast = 2): number {\n const index = ramp.findIndex((step) => contrastRatio(step, surface) >= minContrast);\n return index < 0 ? ramp.length - 1 : index;\n}\n\n/**\n * Build a diverging scale from two opposing hues around a neutral midpoint.\n *\n * The midpoint is **grey, never a hue**: a coloured midpoint reads as a third\n * category instead of as \"no deviation\", which is the one thing a diverging scale\n * exists to show. The arms get equal step counts so neither side looks like it\n * carries more range than the other.\n *\n * @param params.coolHue - OKLCH hue for the negative arm.\n * @param params.warmHue - OKLCH hue for the positive arm.\n * @param params.mid - Neutral midpoint, in hex.\n * @param params.mode - Which lightness band to span.\n * @param params.steps - Steps per arm.\n * @returns The scale, each arm ordered extreme → nearest the midpoint.\n */\nexport function buildDivergingRamp({\n coolHue,\n warmHue,\n mid,\n mode,\n steps = DIVERGING_ARM_STEPS,\n}: {\n coolHue: number;\n warmHue: number;\n mid: string;\n mode: \"light\" | \"dark\";\n steps?: number;\n}): DivergingRamp {\n /*\n * Each arm spans from its extreme to just short of the midpoint, so the two\n * arms together read as one continuous scale rather than two ramps abutting.\n */\n const band = mode === \"light\" ? { from: 0.86, to: 0.4 } : { from: 0.82, to: 0.42 };\n const arm = (hue: number): string[] => {\n const out: string[] = [];\n for (let i = 0; i < steps; i += 1) {\n const t = steps === 1 ? 0 : i / (steps - 1);\n out.push(\n oklchToHex({\n l: band.from + (band.to - band.from) * t,\n c: 0.17 * chromaDome(1 - t * 0.5),\n h: hue,\n }),\n );\n }\n return out.reverse();\n };\n return { cool: arm(coolHue), mid, warm: [...arm(warmHue)].reverse() };\n}\n\n/**\n * The hue of a hex colour, for feeding the ramp builders.\n *\n * @param hex - Any hex colour.\n * @returns Its OKLCH hue in degrees.\n */\nexport function hueOf(hex: string): number {\n return hexToOklch(hex).h;\n}\n"],"mappings":"+BAsBA,IAAM,EAAO,CACT,MAAO,CAAE,KAAM,IAAM,GAAI,GAAK,EAC9B,KAAM,CAAE,KAAM,IAAM,GAAI,GAAK,CACjC,EAYA,SAAS,EAAW,EAAmB,CACnC,MAAO,KAAO,KAAQ,EAAI,KAAK,IAAI,EAAI,EAAI,CAAC,GAAK,IACrD,CA6BA,SAAgB,EACZ,EACA,EACA,CAAE,QAAA,EAA0B,aAAa,KAA2B,CAAC,EAC7D,CACR,IAAM,EAAO,EAAK,GACZ,EAAgB,CAAC,EACvB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,GAAK,EAAG,CAC/B,IAAM,EAAI,IAAU,EAAI,EAAI,GAAK,EAAQ,GACzC,EAAI,KACA,EAAA,WAAW,CACP,EAAG,EAAK,MAAQ,EAAK,GAAK,EAAK,MAAQ,EACvC,EAAG,EAAa,EAAW,CAAC,EAC5B,EAAG,CACP,CAAC,CACL,CACJ,CACA,OAAO,CACX,CAmCA,SAAgB,EAAmB,CAC/B,UACA,UACA,MACA,OACA,QAAA,GAOc,CAKd,IAAM,EAAO,IAAS,QAAU,CAAE,KAAM,IAAM,GAAI,EAAI,EAAI,CAAE,KAAM,IAAM,GAAI,GAAK,EAC3E,EAAO,GAA0B,CACnC,IAAM,EAAgB,CAAC,EACvB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,GAAK,EAAG,CAC/B,IAAM,EAAI,IAAU,EAAI,EAAI,GAAK,EAAQ,GACzC,EAAI,KACA,EAAA,WAAW,CACP,EAAG,EAAK,MAAQ,EAAK,GAAK,EAAK,MAAQ,EACvC,EAAG,IAAO,EAAW,EAAI,EAAI,EAAG,EAChC,EAAG,CACP,CAAC,CACL,CACJ,CACA,OAAO,EAAI,QAAQ,CACvB,EACA,MAAO,CAAE,KAAM,EAAI,CAAO,EAAG,MAAK,KAAM,CAAC,GAAG,EAAI,CAAO,CAAC,CAAC,CAAC,QAAQ,CAAE,CACxE,CAQA,SAAgB,EAAM,EAAqB,CACvC,OAAO,EAAA,WAAW,CAAG,CAAC,CAAC,CAC3B"}
1
+ {"version":3,"file":"data-viz-ramps.cjs","names":["oklchToHex","hexToOklch","require_color","BAND","chromaDome","t","buildRamp","band","mode","out","i","steps","peakChroma","hue","buildDivergingRamp","arm","coolHue","warmHue","hueOf","hex"],"sources":["../../src/theme/data-viz-ramps.ts"],"sourcesContent":["import { contrastRatio, hexToOklch, oklchToHex } from \"./color\";\n\n/** Number of steps in a sequential ramp. */\nexport const SEQUENTIAL_STEPS = 7;\n\n/** Steps per arm of a diverging scale, excluding the neutral midpoint. */\nexport const DIVERGING_ARM_STEPS = 4;\n\n/** A diverging scale: cool arm (extreme → near-mid), the midpoint, then the warm arm. */\nexport interface DivergingRamp {\n cool: string[];\n mid: string;\n warm: string[];\n}\n\n/**\n * Lightness range a ramp spans, per mode.\n *\n * Dark mode is **selected, not flipped**: its own band, chosen for the dark surface.\n * Mechanically inverting the light ramp yields steps that are either invisible\n * against a near-black surface or so bright they read as highlights.\n */\nconst BAND = {\n light: { from: 0.93, to: 0.34 },\n dark: { from: 0.28, to: 0.86 },\n} as const;\n\n/**\n * Chroma shaped as a dome across the ramp.\n *\n * A constant chroma makes the pale end look muddy and the dark end look neon. The\n * dome keeps the extremes believable while the middle carries the hue, which is\n * what makes a heatmap readable at a glance.\n *\n * @param t - Position along the ramp, `0`–`1`.\n * @returns A multiplier for the peak chroma.\n */\nfunction chromaDome(t: number): number {\n return 0.35 + 0.65 * (1 - Math.abs(2 * t - 1) ** 1.6);\n}\n\nexport interface BuildRampOptions {\n /** How many steps to emit. Defaults to {@link SEQUENTIAL_STEPS}. */\n steps?: number;\n /** Chroma at the middle of the ramp. */\n peakChroma?: number;\n}\n\n/**\n * Build a single-hue ramp with evenly spaced perceptual lightness.\n *\n * Even spacing in OKLCH lightness — not in RGB — is what makes equal data steps look\n * like equal colour steps.\n *\n * Steps come back in **token order**: index 0 is the end that means \"near zero\", so\n * it is the lightest on a light canvas and the darkest on a dark one. That is the\n * order `--tempest-chart-sequential-1…7` is written in, and it makes index 0 the step\n * nearest the surface in both modes — which is what `ordinalStart` walks from.\n * Returning a fixed light→dark order instead would put token 1 at opposite ends of\n * the scale depending on the mode, and a dark theme would paint every heatmap\n * inverted.\n *\n * @param hue - OKLCH hue in degrees.\n * @param mode - Which lightness band to span.\n * @param options - Shape of the ramp: `steps` (how many to emit) and `peakChroma`\n * (chroma at the middle).\n * @returns Hex steps, near-zero end first.\n */\nexport function buildRamp(\n hue: number,\n mode: \"light\" | \"dark\",\n { steps = SEQUENTIAL_STEPS, peakChroma = 0.19 }: BuildRampOptions = {},\n): string[] {\n const band = BAND[mode];\n const out: string[] = [];\n for (let i = 0; i < steps; i += 1) {\n const t = steps === 1 ? 0 : i / (steps - 1);\n out.push(\n oklchToHex({\n l: band.from + (band.to - band.from) * t,\n c: peakChroma * chromaDome(t),\n h: hue,\n }),\n );\n }\n return out;\n}\n\n/**\n * The first index of `ramp` that clears `minContrast` against `surface`.\n *\n * A **sequential** ramp may let its near-zero end recede into the surface — that is\n * what \"almost nothing\" should look like on a heatmap. An **ordinal** ramp may not:\n * every step is a discrete mark a reader has to see. This is how a consumer finds\n * where the ordinal-safe slice of a sequential ramp begins.\n *\n * @param ramp - Hex steps in token order, near-zero end first.\n * @param surface - The chart surface the ramp sits on.\n * @param minContrast - Floor to clear. Default `2` — the ordinal floor.\n * @returns The first safe index, or `0` when every step already clears it.\n */\nexport function ordinalStart(ramp: string[], surface: string, minContrast = 2): number {\n const index = ramp.findIndex((step) => contrastRatio(step, surface) >= minContrast);\n return index < 0 ? ramp.length - 1 : index;\n}\n\n/**\n * Build a diverging scale from two opposing hues around a neutral midpoint.\n *\n * The midpoint is **grey, never a hue**: a coloured midpoint reads as a third\n * category instead of as \"no deviation\", which is the one thing a diverging scale\n * exists to show. The arms get equal step counts so neither side looks like it\n * carries more range than the other.\n *\n * @param params.coolHue - OKLCH hue for the negative arm.\n * @param params.warmHue - OKLCH hue for the positive arm.\n * @param params.mid - Neutral midpoint, in hex.\n * @param params.mode - Which lightness band to span.\n * @param params.steps - Steps per arm.\n * @returns The scale, each arm ordered extreme → nearest the midpoint.\n */\nexport function buildDivergingRamp({\n coolHue,\n warmHue,\n mid,\n mode,\n steps = DIVERGING_ARM_STEPS,\n}: {\n coolHue: number;\n warmHue: number;\n mid: string;\n mode: \"light\" | \"dark\";\n steps?: number;\n}): DivergingRamp {\n /*\n * Each arm spans from its extreme to just short of the midpoint, so the two\n * arms together read as one continuous scale rather than two ramps abutting.\n */\n const band = mode === \"light\" ? { from: 0.86, to: 0.4 } : { from: 0.82, to: 0.42 };\n const arm = (hue: number): string[] => {\n const out: string[] = [];\n for (let i = 0; i < steps; i += 1) {\n const t = steps === 1 ? 0 : i / (steps - 1);\n out.push(\n oklchToHex({\n l: band.from + (band.to - band.from) * t,\n c: 0.17 * chromaDome(1 - t * 0.5),\n h: hue,\n }),\n );\n }\n return out.reverse();\n };\n return { cool: arm(coolHue), mid, warm: [...arm(warmHue)].reverse() };\n}\n\n/**\n * The hue of a hex colour, for feeding the ramp builders.\n *\n * @param hex - Any hex colour.\n * @returns Its OKLCH hue in degrees.\n */\nexport function hueOf(hex: string): number {\n return hexToOklch(hex).h;\n}\n"],"mappings":"A,+BAsBA,IAAMG,EAAO,CACT,MAAO,CAAE,KAAM,IAAM,GAAI,GAAK,EAC9B,KAAM,CAAE,KAAM,IAAM,GAAI,GAAK,CACjC,EAYA,SAASC,EAAW,EAAmB,CACnC,MAAO,KAAO,KAAQ,EAAI,KAAK,IAAI,EAAIC,EAAI,CAAC,GAAK,IACrD,CA6BA,SAAgBC,EACZ,EACA,EACA,CAAE,QAAA,EAA0B,aAAa,KAA2B,CAAC,EAC7D,CACR,IAAMC,EAAOJ,EAAKK,GACZC,EAAgB,CAAC,EACvB,IAAK,IAAIC,EAAI,EAAGA,EAAIC,EAAO,GAAK,EAAG,CAC/B,IAAMN,EAAIM,IAAU,EAAI,EAAID,GAAKC,EAAQ,GACzCF,EAAI,KACAT,EAAAA,WAAW,CACP,EAAGO,EAAK,MAAQA,EAAK,GAAKA,EAAK,MAAQF,EACvC,EAAGO,EAAaR,EAAWC,CAAC,EAC5B,EAAGQ,CACP,CAAC,CACL,CACJ,CACA,OAAOJ,CACX,CAmCA,SAAgBK,EAAmB,CAC/B,UACA,UACA,MACA,OACA,QAAA,GAOc,CAKd,IAAMP,EAAOC,IAAS,QAAU,CAAE,KAAM,IAAM,GAAI,EAAI,EAAI,CAAE,KAAM,IAAM,GAAI,GAAK,EAC3EO,EAAO,GAA0B,CACnC,IAAMN,EAAgB,CAAC,EACvB,IAAK,IAAI,EAAI,EAAG,EAAIE,EAAO,GAAK,EAAG,CAC/B,IAAMN,EAAIM,IAAU,EAAI,EAAI,GAAKA,EAAQ,GACzCF,EAAI,KACAT,EAAAA,WAAW,CACP,EAAGO,EAAK,MAAQA,EAAK,GAAKA,EAAK,MAAQF,EACvC,EAAG,IAAOD,EAAW,EAAIC,EAAI,EAAG,EAChC,EAAGQ,CACP,CAAC,CACL,CACJ,CACA,OAAOJ,EAAI,QAAQ,CACvB,EACA,MAAO,CAAE,KAAMM,EAAIC,CAAO,EAAG,MAAK,KAAM,CAAC,GAAGD,EAAIE,CAAO,CAAC,CAAC,CAAC,QAAQ,CAAE,CACxE,CAQA,SAAgBC,EAAM,EAAqB,CACvC,OAAOjB,EAAAA,WAAWkB,CAAG,CAAC,CAAC,CAC3B,C"}