@tenphi/tasty 0.1.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 (359) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +236 -0
  3. package/dist/_virtual/_rolldown/runtime.mjs +7 -0
  4. package/dist/chunks/cacheKey.d.ts +1 -0
  5. package/dist/chunks/cacheKey.js +70 -0
  6. package/dist/chunks/cacheKey.js.map +1 -0
  7. package/dist/chunks/cacheKey.mjs +70 -0
  8. package/dist/chunks/cacheKey.mjs.map +1 -0
  9. package/dist/chunks/definitions.d.ts +37 -0
  10. package/dist/chunks/definitions.js +260 -0
  11. package/dist/chunks/definitions.js.map +1 -0
  12. package/dist/chunks/definitions.mjs +260 -0
  13. package/dist/chunks/definitions.mjs.map +1 -0
  14. package/dist/chunks/index.d.ts +3 -0
  15. package/dist/chunks/renderChunk.d.ts +2 -0
  16. package/dist/chunks/renderChunk.js +61 -0
  17. package/dist/chunks/renderChunk.js.map +1 -0
  18. package/dist/chunks/renderChunk.mjs +61 -0
  19. package/dist/chunks/renderChunk.mjs.map +1 -0
  20. package/dist/config.d.ts +279 -0
  21. package/dist/config.js +400 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/config.mjs +231 -0
  24. package/dist/config.mjs.map +1 -0
  25. package/dist/css-writer.d.mts +45 -0
  26. package/dist/css-writer.mjs +74 -0
  27. package/dist/css-writer.mjs.map +1 -0
  28. package/dist/debug.d.ts +204 -0
  29. package/dist/debug.js +733 -0
  30. package/dist/debug.js.map +1 -0
  31. package/dist/extractor.d.mts +24 -0
  32. package/dist/extractor.mjs +150 -0
  33. package/dist/extractor.mjs.map +1 -0
  34. package/dist/hooks/index.d.ts +5 -0
  35. package/dist/hooks/useGlobalStyles.d.ts +27 -0
  36. package/dist/hooks/useGlobalStyles.js +56 -0
  37. package/dist/hooks/useGlobalStyles.js.map +1 -0
  38. package/dist/hooks/useKeyframes.d.ts +56 -0
  39. package/dist/hooks/useKeyframes.js +54 -0
  40. package/dist/hooks/useKeyframes.js.map +1 -0
  41. package/dist/hooks/useProperty.d.ts +79 -0
  42. package/dist/hooks/useProperty.js +91 -0
  43. package/dist/hooks/useProperty.js.map +1 -0
  44. package/dist/hooks/useRawCSS.d.ts +53 -0
  45. package/dist/hooks/useRawCSS.js +28 -0
  46. package/dist/hooks/useRawCSS.js.map +1 -0
  47. package/dist/hooks/useStyles.d.ts +40 -0
  48. package/dist/hooks/useStyles.js +169 -0
  49. package/dist/hooks/useStyles.js.map +1 -0
  50. package/dist/index.d.ts +38 -0
  51. package/dist/index.js +30 -0
  52. package/dist/injector/index.d.ts +157 -0
  53. package/dist/injector/index.js +154 -0
  54. package/dist/injector/index.js.map +1 -0
  55. package/dist/injector/injector.d.ts +139 -0
  56. package/dist/injector/injector.js +404 -0
  57. package/dist/injector/injector.js.map +1 -0
  58. package/dist/injector/injector.mjs +404 -0
  59. package/dist/injector/injector.mjs.map +1 -0
  60. package/dist/injector/sheet-manager.d.ts +127 -0
  61. package/dist/injector/sheet-manager.js +714 -0
  62. package/dist/injector/sheet-manager.js.map +1 -0
  63. package/dist/injector/sheet-manager.mjs +714 -0
  64. package/dist/injector/sheet-manager.mjs.map +1 -0
  65. package/dist/injector/types.d.mts +18 -0
  66. package/dist/injector/types.d.ts +135 -0
  67. package/dist/keyframes/index.js +206 -0
  68. package/dist/keyframes/index.js.map +1 -0
  69. package/dist/keyframes/index.mjs +156 -0
  70. package/dist/keyframes/index.mjs.map +1 -0
  71. package/dist/parser/classify.js +319 -0
  72. package/dist/parser/classify.js.map +1 -0
  73. package/dist/parser/classify.mjs +319 -0
  74. package/dist/parser/classify.mjs.map +1 -0
  75. package/dist/parser/const.js +33 -0
  76. package/dist/parser/const.js.map +1 -0
  77. package/dist/parser/const.mjs +33 -0
  78. package/dist/parser/const.mjs.map +1 -0
  79. package/dist/parser/lru.js +109 -0
  80. package/dist/parser/lru.js.map +1 -0
  81. package/dist/parser/lru.mjs +109 -0
  82. package/dist/parser/lru.mjs.map +1 -0
  83. package/dist/parser/parser.d.ts +25 -0
  84. package/dist/parser/parser.js +116 -0
  85. package/dist/parser/parser.js.map +1 -0
  86. package/dist/parser/parser.mjs +116 -0
  87. package/dist/parser/parser.mjs.map +1 -0
  88. package/dist/parser/tokenizer.js +69 -0
  89. package/dist/parser/tokenizer.js.map +1 -0
  90. package/dist/parser/tokenizer.mjs +69 -0
  91. package/dist/parser/tokenizer.mjs.map +1 -0
  92. package/dist/parser/types.d.mts +37 -0
  93. package/dist/parser/types.d.ts +46 -0
  94. package/dist/parser/types.js +46 -0
  95. package/dist/parser/types.js.map +1 -0
  96. package/dist/parser/types.mjs +46 -0
  97. package/dist/parser/types.mjs.map +1 -0
  98. package/dist/pipeline/conditions.js +377 -0
  99. package/dist/pipeline/conditions.js.map +1 -0
  100. package/dist/pipeline/conditions.mjs +377 -0
  101. package/dist/pipeline/conditions.mjs.map +1 -0
  102. package/dist/pipeline/exclusive.d.ts +1 -0
  103. package/dist/pipeline/exclusive.js +231 -0
  104. package/dist/pipeline/exclusive.js.map +1 -0
  105. package/dist/pipeline/exclusive.mjs +231 -0
  106. package/dist/pipeline/exclusive.mjs.map +1 -0
  107. package/dist/pipeline/index.d.ts +53 -0
  108. package/dist/pipeline/index.js +641 -0
  109. package/dist/pipeline/index.js.map +1 -0
  110. package/dist/pipeline/index.mjs +635 -0
  111. package/dist/pipeline/index.mjs.map +1 -0
  112. package/dist/pipeline/materialize.js +821 -0
  113. package/dist/pipeline/materialize.js.map +1 -0
  114. package/dist/pipeline/materialize.mjs +821 -0
  115. package/dist/pipeline/materialize.mjs.map +1 -0
  116. package/dist/pipeline/parseStateKey.d.ts +1 -0
  117. package/dist/pipeline/parseStateKey.js +418 -0
  118. package/dist/pipeline/parseStateKey.js.map +1 -0
  119. package/dist/pipeline/parseStateKey.mjs +418 -0
  120. package/dist/pipeline/parseStateKey.mjs.map +1 -0
  121. package/dist/pipeline/simplify.js +557 -0
  122. package/dist/pipeline/simplify.js.map +1 -0
  123. package/dist/pipeline/simplify.mjs +557 -0
  124. package/dist/pipeline/simplify.mjs.map +1 -0
  125. package/dist/plugins/index.d.ts +2 -0
  126. package/dist/plugins/okhsl-plugin.d.ts +35 -0
  127. package/dist/plugins/okhsl-plugin.js +371 -0
  128. package/dist/plugins/okhsl-plugin.js.map +1 -0
  129. package/dist/plugins/okhsl-plugin.mjs +345 -0
  130. package/dist/plugins/okhsl-plugin.mjs.map +1 -0
  131. package/dist/plugins/types.d.mts +49 -0
  132. package/dist/plugins/types.d.ts +69 -0
  133. package/dist/properties/index.js +158 -0
  134. package/dist/properties/index.js.map +1 -0
  135. package/dist/properties/index.mjs +141 -0
  136. package/dist/properties/index.mjs.map +1 -0
  137. package/dist/states/index.d.ts +45 -0
  138. package/dist/states/index.js +389 -0
  139. package/dist/states/index.js.map +1 -0
  140. package/dist/states/index.mjs +161 -0
  141. package/dist/states/index.mjs.map +1 -0
  142. package/dist/static/index.d.ts +5 -0
  143. package/dist/static/index.js +5 -0
  144. package/dist/static/tastyStatic.d.ts +46 -0
  145. package/dist/static/tastyStatic.js +31 -0
  146. package/dist/static/tastyStatic.js.map +1 -0
  147. package/dist/static/types.d.ts +49 -0
  148. package/dist/static/types.js +24 -0
  149. package/dist/static/types.js.map +1 -0
  150. package/dist/styles/align.d.ts +15 -0
  151. package/dist/styles/align.js +14 -0
  152. package/dist/styles/align.js.map +1 -0
  153. package/dist/styles/align.mjs +14 -0
  154. package/dist/styles/align.mjs.map +1 -0
  155. package/dist/styles/border.d.ts +25 -0
  156. package/dist/styles/border.js +114 -0
  157. package/dist/styles/border.js.map +1 -0
  158. package/dist/styles/border.mjs +114 -0
  159. package/dist/styles/border.mjs.map +1 -0
  160. package/dist/styles/color.d.ts +14 -0
  161. package/dist/styles/color.js +23 -0
  162. package/dist/styles/color.js.map +1 -0
  163. package/dist/styles/color.mjs +23 -0
  164. package/dist/styles/color.mjs.map +1 -0
  165. package/dist/styles/createStyle.js +77 -0
  166. package/dist/styles/createStyle.js.map +1 -0
  167. package/dist/styles/createStyle.mjs +77 -0
  168. package/dist/styles/createStyle.mjs.map +1 -0
  169. package/dist/styles/dimension.js +97 -0
  170. package/dist/styles/dimension.js.map +1 -0
  171. package/dist/styles/dimension.mjs +97 -0
  172. package/dist/styles/dimension.mjs.map +1 -0
  173. package/dist/styles/display.d.ts +37 -0
  174. package/dist/styles/display.js +67 -0
  175. package/dist/styles/display.js.map +1 -0
  176. package/dist/styles/display.mjs +67 -0
  177. package/dist/styles/display.mjs.map +1 -0
  178. package/dist/styles/fade.d.ts +15 -0
  179. package/dist/styles/fade.js +58 -0
  180. package/dist/styles/fade.js.map +1 -0
  181. package/dist/styles/fade.mjs +58 -0
  182. package/dist/styles/fade.mjs.map +1 -0
  183. package/dist/styles/fill.d.ts +44 -0
  184. package/dist/styles/fill.js +51 -0
  185. package/dist/styles/fill.js.map +1 -0
  186. package/dist/styles/fill.mjs +51 -0
  187. package/dist/styles/fill.mjs.map +1 -0
  188. package/dist/styles/flow.d.ts +16 -0
  189. package/dist/styles/flow.js +12 -0
  190. package/dist/styles/flow.js.map +1 -0
  191. package/dist/styles/flow.mjs +12 -0
  192. package/dist/styles/flow.mjs.map +1 -0
  193. package/dist/styles/gap.d.ts +31 -0
  194. package/dist/styles/gap.js +37 -0
  195. package/dist/styles/gap.js.map +1 -0
  196. package/dist/styles/gap.mjs +37 -0
  197. package/dist/styles/gap.mjs.map +1 -0
  198. package/dist/styles/height.d.ts +17 -0
  199. package/dist/styles/height.js +20 -0
  200. package/dist/styles/height.js.map +1 -0
  201. package/dist/styles/height.mjs +20 -0
  202. package/dist/styles/height.mjs.map +1 -0
  203. package/dist/styles/index.d.ts +2 -0
  204. package/dist/styles/index.js +9 -0
  205. package/dist/styles/index.js.map +1 -0
  206. package/dist/styles/index.mjs +9 -0
  207. package/dist/styles/index.mjs.map +1 -0
  208. package/dist/styles/inset.d.ts +50 -0
  209. package/dist/styles/inset.js +142 -0
  210. package/dist/styles/inset.js.map +1 -0
  211. package/dist/styles/inset.mjs +142 -0
  212. package/dist/styles/inset.mjs.map +1 -0
  213. package/dist/styles/justify.d.ts +15 -0
  214. package/dist/styles/justify.js +14 -0
  215. package/dist/styles/justify.js.map +1 -0
  216. package/dist/styles/justify.mjs +14 -0
  217. package/dist/styles/justify.mjs.map +1 -0
  218. package/dist/styles/list.d.ts +16 -0
  219. package/dist/styles/list.js +98 -0
  220. package/dist/styles/list.js.map +1 -0
  221. package/dist/styles/margin.d.ts +28 -0
  222. package/dist/styles/margin.js +96 -0
  223. package/dist/styles/margin.js.map +1 -0
  224. package/dist/styles/margin.mjs +96 -0
  225. package/dist/styles/margin.mjs.map +1 -0
  226. package/dist/styles/outline.d.ts +29 -0
  227. package/dist/styles/outline.js +65 -0
  228. package/dist/styles/outline.js.map +1 -0
  229. package/dist/styles/outline.mjs +65 -0
  230. package/dist/styles/outline.mjs.map +1 -0
  231. package/dist/styles/padding.d.ts +28 -0
  232. package/dist/styles/padding.js +96 -0
  233. package/dist/styles/padding.js.map +1 -0
  234. package/dist/styles/padding.mjs +96 -0
  235. package/dist/styles/padding.mjs.map +1 -0
  236. package/dist/styles/predefined.d.ts +74 -0
  237. package/dist/styles/predefined.js +241 -0
  238. package/dist/styles/predefined.js.map +1 -0
  239. package/dist/styles/predefined.mjs +232 -0
  240. package/dist/styles/predefined.mjs.map +1 -0
  241. package/dist/styles/preset.d.ts +47 -0
  242. package/dist/styles/preset.js +126 -0
  243. package/dist/styles/preset.js.map +1 -0
  244. package/dist/styles/preset.mjs +126 -0
  245. package/dist/styles/preset.mjs.map +1 -0
  246. package/dist/styles/radius.d.ts +14 -0
  247. package/dist/styles/radius.js +51 -0
  248. package/dist/styles/radius.js.map +1 -0
  249. package/dist/styles/radius.mjs +51 -0
  250. package/dist/styles/radius.mjs.map +1 -0
  251. package/dist/styles/scrollbar.d.ts +21 -0
  252. package/dist/styles/scrollbar.js +105 -0
  253. package/dist/styles/scrollbar.js.map +1 -0
  254. package/dist/styles/scrollbar.mjs +105 -0
  255. package/dist/styles/scrollbar.mjs.map +1 -0
  256. package/dist/styles/shadow.d.ts +14 -0
  257. package/dist/styles/shadow.js +24 -0
  258. package/dist/styles/shadow.js.map +1 -0
  259. package/dist/styles/shadow.mjs +24 -0
  260. package/dist/styles/shadow.mjs.map +1 -0
  261. package/dist/styles/styledScrollbar.d.ts +47 -0
  262. package/dist/styles/styledScrollbar.js +38 -0
  263. package/dist/styles/styledScrollbar.js.map +1 -0
  264. package/dist/styles/styledScrollbar.mjs +38 -0
  265. package/dist/styles/styledScrollbar.mjs.map +1 -0
  266. package/dist/styles/transition.d.ts +14 -0
  267. package/dist/styles/transition.js +138 -0
  268. package/dist/styles/transition.js.map +1 -0
  269. package/dist/styles/transition.mjs +138 -0
  270. package/dist/styles/transition.mjs.map +1 -0
  271. package/dist/styles/types.d.mts +492 -0
  272. package/dist/styles/types.d.ts +496 -0
  273. package/dist/styles/width.d.ts +17 -0
  274. package/dist/styles/width.js +20 -0
  275. package/dist/styles/width.js.map +1 -0
  276. package/dist/styles/width.mjs +20 -0
  277. package/dist/styles/width.mjs.map +1 -0
  278. package/dist/tasty.d.ts +983 -0
  279. package/dist/tasty.js +191 -0
  280. package/dist/tasty.js.map +1 -0
  281. package/dist/tokens/typography.d.ts +19 -0
  282. package/dist/tokens/typography.js +237 -0
  283. package/dist/tokens/typography.js.map +1 -0
  284. package/dist/types.d.ts +182 -0
  285. package/dist/utils/cache-wrapper.js +26 -0
  286. package/dist/utils/cache-wrapper.js.map +1 -0
  287. package/dist/utils/cache-wrapper.mjs +26 -0
  288. package/dist/utils/cache-wrapper.mjs.map +1 -0
  289. package/dist/utils/case-converter.js +8 -0
  290. package/dist/utils/case-converter.js.map +1 -0
  291. package/dist/utils/case-converter.mjs +8 -0
  292. package/dist/utils/case-converter.mjs.map +1 -0
  293. package/dist/utils/colors.d.ts +5 -0
  294. package/dist/utils/colors.js +9 -0
  295. package/dist/utils/colors.js.map +1 -0
  296. package/dist/utils/dotize.d.ts +26 -0
  297. package/dist/utils/dotize.js +122 -0
  298. package/dist/utils/dotize.js.map +1 -0
  299. package/dist/utils/filter-base-props.d.ts +15 -0
  300. package/dist/utils/filter-base-props.js +45 -0
  301. package/dist/utils/filter-base-props.js.map +1 -0
  302. package/dist/utils/get-display-name.d.ts +7 -0
  303. package/dist/utils/get-display-name.js +10 -0
  304. package/dist/utils/get-display-name.js.map +1 -0
  305. package/dist/utils/hsl-to-rgb.js +38 -0
  306. package/dist/utils/hsl-to-rgb.js.map +1 -0
  307. package/dist/utils/hsl-to-rgb.mjs +38 -0
  308. package/dist/utils/hsl-to-rgb.mjs.map +1 -0
  309. package/dist/utils/is-dev-env.js +19 -0
  310. package/dist/utils/is-dev-env.js.map +1 -0
  311. package/dist/utils/is-dev-env.mjs +19 -0
  312. package/dist/utils/is-dev-env.mjs.map +1 -0
  313. package/dist/utils/merge-styles.d.ts +7 -0
  314. package/dist/utils/merge-styles.js +146 -0
  315. package/dist/utils/merge-styles.js.map +1 -0
  316. package/dist/utils/merge-styles.mjs +146 -0
  317. package/dist/utils/merge-styles.mjs.map +1 -0
  318. package/dist/utils/mod-attrs.d.ts +8 -0
  319. package/dist/utils/mod-attrs.js +21 -0
  320. package/dist/utils/mod-attrs.js.map +1 -0
  321. package/dist/utils/okhsl-to-rgb.js +296 -0
  322. package/dist/utils/okhsl-to-rgb.js.map +1 -0
  323. package/dist/utils/okhsl-to-rgb.mjs +296 -0
  324. package/dist/utils/okhsl-to-rgb.mjs.map +1 -0
  325. package/dist/utils/process-tokens.d.ts +31 -0
  326. package/dist/utils/process-tokens.js +171 -0
  327. package/dist/utils/process-tokens.js.map +1 -0
  328. package/dist/utils/process-tokens.mjs +28 -0
  329. package/dist/utils/process-tokens.mjs.map +1 -0
  330. package/dist/utils/resolve-recipes.d.ts +17 -0
  331. package/dist/utils/resolve-recipes.js +143 -0
  332. package/dist/utils/resolve-recipes.js.map +1 -0
  333. package/dist/utils/resolve-recipes.mjs +143 -0
  334. package/dist/utils/resolve-recipes.mjs.map +1 -0
  335. package/dist/utils/string.js +8 -0
  336. package/dist/utils/string.js.map +1 -0
  337. package/dist/utils/string.mjs +8 -0
  338. package/dist/utils/string.mjs.map +1 -0
  339. package/dist/utils/styles.d.mts +18 -0
  340. package/dist/utils/styles.d.ts +183 -0
  341. package/dist/utils/styles.js +585 -0
  342. package/dist/utils/styles.js.map +1 -0
  343. package/dist/utils/styles.mjs +346 -0
  344. package/dist/utils/styles.mjs.map +1 -0
  345. package/dist/utils/typography.d.ts +36 -0
  346. package/dist/utils/typography.js +53 -0
  347. package/dist/utils/typography.js.map +1 -0
  348. package/dist/utils/warnings.d.ts +16 -0
  349. package/dist/utils/warnings.js +16 -0
  350. package/dist/utils/warnings.js.map +1 -0
  351. package/dist/zero/babel.d.mts +108 -0
  352. package/dist/zero/babel.mjs +282 -0
  353. package/dist/zero/babel.mjs.map +1 -0
  354. package/dist/zero/index.d.mts +3 -0
  355. package/dist/zero/index.mjs +4 -0
  356. package/dist/zero/next.d.mts +60 -0
  357. package/dist/zero/next.mjs +78 -0
  358. package/dist/zero/next.mjs.map +1 -0
  359. package/package.json +127 -0
@@ -0,0 +1,345 @@
1
+ import { Lru } from "../parser/lru.mjs";
2
+
3
+ //#region src/plugins/okhsl-plugin.ts
4
+ /**
5
+ * OKHSL Plugin for Tasty
6
+ *
7
+ * Converts OKHSL color syntax to RGB notation.
8
+ * Supports angle units: deg, turn, rad, or unitless (degrees).
9
+ *
10
+ * Examples:
11
+ * okhsl(240.5 50% 50%)
12
+ * okhsl(240.5deg 50% 50%)
13
+ * okhsl(0.25turn 50% 50%)
14
+ * okhsl(1.57rad 50% 50%)
15
+ *
16
+ * Conversion math inlined from @texel/color to avoid external dependencies.
17
+ */
18
+ const conversionCache = new Lru(500);
19
+ const OKLab_to_LMS_M = [
20
+ [
21
+ 1,
22
+ .3963377773761749,
23
+ .2158037573099136
24
+ ],
25
+ [
26
+ 1,
27
+ -.1055613458156586,
28
+ -.0638541728258133
29
+ ],
30
+ [
31
+ 1,
32
+ -.0894841775298119,
33
+ -1.2914855480194092
34
+ ]
35
+ ];
36
+ const LMS_to_linear_sRGB_M = [
37
+ [
38
+ 4.076741636075959,
39
+ -3.307711539258062,
40
+ .2309699031821041
41
+ ],
42
+ [
43
+ -1.2684379732850313,
44
+ 2.6097573492876878,
45
+ -.3413193760026569
46
+ ],
47
+ [
48
+ -.004196076138675526,
49
+ -.703418617935936,
50
+ 1.7076146940746113
51
+ ]
52
+ ];
53
+ const OKLab_to_linear_sRGB_coefficients = [
54
+ [[-1.8817030993265873, -.8093650129914302], [
55
+ 1.19086277,
56
+ 1.76576728,
57
+ .59662641,
58
+ .75515197,
59
+ .56771245
60
+ ]],
61
+ [[1.8144407988010998, -1.194452667805235], [
62
+ .73956515,
63
+ -.45954404,
64
+ .08285427,
65
+ .12541073,
66
+ -.14503204
67
+ ]],
68
+ [[.13110757611180954, 1.813339709266608], [
69
+ 1.35733652,
70
+ -.00915799,
71
+ -1.1513021,
72
+ -.50559606,
73
+ .00692167
74
+ ]]
75
+ ];
76
+ const TAU = 2 * Math.PI;
77
+ const clamp = (value, min, max) => Math.max(Math.min(value, max), min);
78
+ const constrainAngle = (angle) => (angle % 360 + 360) % 360;
79
+ const sRGBLinearToGamma = (val) => {
80
+ const sign = val < 0 ? -1 : 1;
81
+ const abs = Math.abs(val);
82
+ return abs > .0031308 ? sign * (1.055 * Math.pow(abs, 1 / 2.4) - .055) : 12.92 * val;
83
+ };
84
+ const dot3 = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
85
+ const transform = (input, matrix) => [
86
+ dot3(input, matrix[0]),
87
+ dot3(input, matrix[1]),
88
+ dot3(input, matrix[2])
89
+ ];
90
+ const cubed3 = (lms) => [
91
+ lms[0] * lms[0] * lms[0],
92
+ lms[1] * lms[1] * lms[1],
93
+ lms[2] * lms[2] * lms[2]
94
+ ];
95
+ const OKLabToLinearSRGB = (lab) => {
96
+ return transform(cubed3(transform(lab, OKLab_to_LMS_M)), LMS_to_linear_sRGB_M);
97
+ };
98
+ const K1 = .206;
99
+ const K2 = .03;
100
+ const K3 = (1 + K1) / (1 + K2);
101
+ const toeInv = (x) => (x ** 2 + K1 * x) / (K3 * (x + K2));
102
+ const dotXY = (a, b) => a[0] * b[0] + a[1] * b[1];
103
+ const computeMaxSaturationOKLC = (a, b) => {
104
+ const okCoeff = OKLab_to_linear_sRGB_coefficients;
105
+ const lmsToRgb = LMS_to_linear_sRGB_M;
106
+ const tmp2 = [a, b];
107
+ const tmp3 = [
108
+ 0,
109
+ a,
110
+ b
111
+ ];
112
+ let chnlCoeff;
113
+ let chnlLMS;
114
+ if (dotXY(okCoeff[0][0], tmp2) > 1) {
115
+ chnlCoeff = okCoeff[0][1];
116
+ chnlLMS = lmsToRgb[0];
117
+ } else if (dotXY(okCoeff[1][0], tmp2) > 1) {
118
+ chnlCoeff = okCoeff[1][1];
119
+ chnlLMS = lmsToRgb[1];
120
+ } else {
121
+ chnlCoeff = okCoeff[2][1];
122
+ chnlLMS = lmsToRgb[2];
123
+ }
124
+ const [k0, k1, k2, k3, k4] = chnlCoeff;
125
+ const [wl, wm, ws] = chnlLMS;
126
+ let sat = k0 + k1 * a + k2 * b + k3 * (a * a) + k4 * a * b;
127
+ const dotYZ = (mat, vec) => mat[1] * vec[1] + mat[2] * vec[2];
128
+ const kl = dotYZ(OKLab_to_LMS_M[0], tmp3);
129
+ const km = dotYZ(OKLab_to_LMS_M[1], tmp3);
130
+ const ks = dotYZ(OKLab_to_LMS_M[2], tmp3);
131
+ const l_ = 1 + sat * kl;
132
+ const m_ = 1 + sat * km;
133
+ const s_ = 1 + sat * ks;
134
+ const l = l_ * l_ * l_;
135
+ const m = m_ * m_ * m_;
136
+ const s = s_ * s_ * s_;
137
+ const lds = 3 * kl * (l_ * l_);
138
+ const mds = 3 * km * (m_ * m_);
139
+ const sds = 3 * ks * (s_ * s_);
140
+ const lds2 = 6 * (kl * kl) * l_;
141
+ const mds2 = 6 * (km * km) * m_;
142
+ const sds2 = 6 * (ks * ks) * s_;
143
+ const f = wl * l + wm * m + ws * s;
144
+ const f1 = wl * lds + wm * mds + ws * sds;
145
+ const f2 = wl * lds2 + wm * mds2 + ws * sds2;
146
+ sat = sat - f * f1 / (f1 * f1 - .5 * f * f2);
147
+ return sat;
148
+ };
149
+ const findCuspOKLCH = (a, b) => {
150
+ const S_cusp = computeMaxSaturationOKLC(a, b);
151
+ const rgb_at_max = OKLabToLinearSRGB([
152
+ 1,
153
+ S_cusp * a,
154
+ S_cusp * b
155
+ ]);
156
+ const L_cusp = Math.cbrt(1 / Math.max(Math.max(rgb_at_max[0], rgb_at_max[1]), Math.max(rgb_at_max[2], 0)));
157
+ return [L_cusp, L_cusp * S_cusp];
158
+ };
159
+ const findGamutIntersectionOKLCH = (a, b, l1, c1, l0, cusp) => {
160
+ const lmsToRgb = LMS_to_linear_sRGB_M;
161
+ const tmp3 = [
162
+ 0,
163
+ a,
164
+ b
165
+ ];
166
+ const floatMax = Number.MAX_VALUE;
167
+ let t;
168
+ const dotYZ = (mat, vec) => mat[1] * vec[1] + mat[2] * vec[2];
169
+ const dotXYZ = (vec, x, y, z) => vec[0] * x + vec[1] * y + vec[2] * z;
170
+ if ((l1 - l0) * cusp[1] - (cusp[0] - l0) * c1 <= 0) {
171
+ const denom = c1 * cusp[0] + cusp[1] * (l0 - l1);
172
+ t = denom === 0 ? 0 : cusp[1] * l0 / denom;
173
+ } else {
174
+ const denom = c1 * (cusp[0] - 1) + cusp[1] * (l0 - l1);
175
+ t = denom === 0 ? 0 : cusp[1] * (l0 - 1) / denom;
176
+ const dl = l1 - l0;
177
+ const dc = c1;
178
+ const kl = dotYZ(OKLab_to_LMS_M[0], tmp3);
179
+ const km = dotYZ(OKLab_to_LMS_M[1], tmp3);
180
+ const ks = dotYZ(OKLab_to_LMS_M[2], tmp3);
181
+ const ldt_ = dl + dc * kl;
182
+ const mdt_ = dl + dc * km;
183
+ const sdt_ = dl + dc * ks;
184
+ const L = l0 * (1 - t) + t * l1;
185
+ const C = t * c1;
186
+ const l_ = L + C * kl;
187
+ const m_ = L + C * km;
188
+ const s_ = L + C * ks;
189
+ const l = l_ * l_ * l_;
190
+ const m = m_ * m_ * m_;
191
+ const s = s_ * s_ * s_;
192
+ const ldt = 3 * ldt_ * l_ * l_;
193
+ const mdt = 3 * mdt_ * m_ * m_;
194
+ const sdt = 3 * sdt_ * s_ * s_;
195
+ const ldt2 = 6 * ldt_ * ldt_ * l_;
196
+ const mdt2 = 6 * mdt_ * mdt_ * m_;
197
+ const sdt2 = 6 * sdt_ * sdt_ * s_;
198
+ const r_ = dotXYZ(lmsToRgb[0], l, m, s) - 1;
199
+ const r1 = dotXYZ(lmsToRgb[0], ldt, mdt, sdt);
200
+ const r2 = dotXYZ(lmsToRgb[0], ldt2, mdt2, sdt2);
201
+ const ur = r1 / (r1 * r1 - .5 * r_ * r2);
202
+ let tr = -r_ * ur;
203
+ const g_ = dotXYZ(lmsToRgb[1], l, m, s) - 1;
204
+ const g1 = dotXYZ(lmsToRgb[1], ldt, mdt, sdt);
205
+ const g2 = dotXYZ(lmsToRgb[1], ldt2, mdt2, sdt2);
206
+ const ug = g1 / (g1 * g1 - .5 * g_ * g2);
207
+ let tg = -g_ * ug;
208
+ const b_ = dotXYZ(lmsToRgb[2], l, m, s) - 1;
209
+ const b1 = dotXYZ(lmsToRgb[2], ldt, mdt, sdt);
210
+ const b2 = dotXYZ(lmsToRgb[2], ldt2, mdt2, sdt2);
211
+ const ub = b1 / (b1 * b1 - .5 * b_ * b2);
212
+ let tb = -b_ * ub;
213
+ tr = ur >= 0 ? tr : floatMax;
214
+ tg = ug >= 0 ? tg : floatMax;
215
+ tb = ub >= 0 ? tb : floatMax;
216
+ t += Math.min(tr, Math.min(tg, tb));
217
+ }
218
+ return t;
219
+ };
220
+ const computeSt = (cusp) => {
221
+ const l = cusp[0];
222
+ const c = cusp[1];
223
+ return [c / l, c / (1 - l)];
224
+ };
225
+ const computeStMid = (a, b) => {
226
+ return [.11516993 + 1 / (7.4477897 + 4.1590124 * b + a * (-2.19557347 + 1.75198401 * b + a * (-2.13704948 - 10.02301043 * b + a * (-4.24894561 + 5.38770819 * b + 4.69891013 * a)))), .11239642 + 1 / (1.6132032 - .68124379 * b + a * (.40370612 + .90148123 * b + a * (-.27087943 + .6122399 * b + a * (.00299215 - .45399568 * b - .14661872 * a))))];
227
+ };
228
+ const getCs = (L, a, b, cusp) => {
229
+ const cMax = findGamutIntersectionOKLCH(a, b, L, 1, L, cusp);
230
+ const stMax = computeSt(cusp);
231
+ const k = cMax / Math.min(L * stMax[0], (1 - L) * stMax[1]);
232
+ const stMid = computeStMid(a, b);
233
+ let ca = L * stMid[0];
234
+ let cb = (1 - L) * stMid[1];
235
+ const cMid = .9 * k * Math.sqrt(Math.sqrt(1 / (1 / ca ** 4 + 1 / cb ** 4)));
236
+ ca = L * .4;
237
+ cb = (1 - L) * .8;
238
+ return [
239
+ Math.sqrt(1 / (1 / ca ** 2 + 1 / cb ** 2)),
240
+ cMid,
241
+ cMax
242
+ ];
243
+ };
244
+ const OKHSLToOKLab = (hsl) => {
245
+ let h = hsl[0];
246
+ const s = hsl[1];
247
+ const l = hsl[2];
248
+ const L = toeInv(l);
249
+ let a = 0;
250
+ let b = 0;
251
+ h = constrainAngle(h) / 360;
252
+ if (L !== 0 && L !== 1 && s !== 0) {
253
+ const a_ = Math.cos(TAU * h);
254
+ const b_ = Math.sin(TAU * h);
255
+ const [c0, cMid, cMax] = getCs(L, a_, b_, findCuspOKLCH(a_, b_));
256
+ const mid = .8;
257
+ const midInv = 1.25;
258
+ let t, k0, k1, k2;
259
+ if (s < mid) {
260
+ t = midInv * s;
261
+ k0 = 0;
262
+ k1 = mid * c0;
263
+ k2 = 1 - k1 / cMid;
264
+ } else {
265
+ t = 5 * (s - .8);
266
+ k0 = cMid;
267
+ k1 = .2 * cMid ** 2 * 1.25 ** 2 / c0;
268
+ k2 = 1 - k1 / (cMax - cMid);
269
+ }
270
+ const c = k0 + t * k1 / (1 - k2 * t);
271
+ a = c * a_;
272
+ b = c * b_;
273
+ }
274
+ return [
275
+ L,
276
+ a,
277
+ b
278
+ ];
279
+ };
280
+ const okhslToSRGB = (h, s, l) => {
281
+ const linearRGB = OKLabToLinearSRGB(OKHSLToOKLab([
282
+ h,
283
+ s,
284
+ l
285
+ ]));
286
+ return [
287
+ clamp(sRGBLinearToGamma(linearRGB[0]), 0, 1),
288
+ clamp(sRGBLinearToGamma(linearRGB[1]), 0, 1),
289
+ clamp(sRGBLinearToGamma(linearRGB[2]), 0, 1)
290
+ ];
291
+ };
292
+ /**
293
+ * Parse an angle value with optional unit.
294
+ * Supports: deg, turn, rad, or unitless (treated as degrees).
295
+ */
296
+ const parseAngle = (value) => {
297
+ const match = value.match(/^([+-]?\d*\.?\d+)(deg|turn|rad)?$/);
298
+ if (!match) return 0;
299
+ const num = parseFloat(match[1]);
300
+ switch (match[2]) {
301
+ case "turn": return num * 360;
302
+ case "rad": return num * 180 / Math.PI;
303
+ default: return num;
304
+ }
305
+ };
306
+ /**
307
+ * Parse a percentage value (e.g., "50%") to a 0-1 range.
308
+ */
309
+ const parsePercentage = (value) => {
310
+ const match = value.match(/^([+-]?\d*\.?\d+)%?$/);
311
+ if (!match) return 0;
312
+ const num = parseFloat(match[1]);
313
+ return value.includes("%") ? num / 100 : num;
314
+ };
315
+ /**
316
+ * The okhsl function handler for tasty parser.
317
+ * Receives parsed style groups and returns an RGB color string.
318
+ */
319
+ const okhslFunc = (groups) => {
320
+ if (groups.length === 0 || groups[0].all.length < 3) {
321
+ console.warn("[okhsl] Expected 3 values (H S L), got:", groups);
322
+ return "rgb(0% 0% 0%)";
323
+ }
324
+ const group = groups[0];
325
+ const tokens = group.all;
326
+ const alpha = group.parts.length > 1 && group.parts[1].all.length > 0 ? group.parts[1].output : void 0;
327
+ const cacheKey = tokens.slice(0, 3).join(" ") + (alpha ? ` / ${alpha}` : "");
328
+ const cached = conversionCache.get(cacheKey);
329
+ if (cached) return cached;
330
+ const h = parseAngle(tokens[0]);
331
+ const s = parsePercentage(tokens[1]);
332
+ const l = parsePercentage(tokens[2]);
333
+ const [r, g, b] = okhslToSRGB(h, clamp(s, 0, 1), clamp(l, 0, 1));
334
+ const format = (n) => {
335
+ const pct = n * 100;
336
+ return parseFloat(pct.toFixed(1)).toString() + "%";
337
+ };
338
+ const result = alpha ? `rgb(${format(r)} ${format(g)} ${format(b)} / ${alpha})` : `rgb(${format(r)} ${format(g)} ${format(b)})`;
339
+ conversionCache.set(cacheKey, result);
340
+ return result;
341
+ };
342
+
343
+ //#endregion
344
+ export { okhslFunc };
345
+ //# sourceMappingURL=okhsl-plugin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"okhsl-plugin.mjs","names":[],"sources":["../../src/plugins/okhsl-plugin.ts"],"sourcesContent":["/**\n * OKHSL Plugin for Tasty\n *\n * Converts OKHSL color syntax to RGB notation.\n * Supports angle units: deg, turn, rad, or unitless (degrees).\n *\n * Examples:\n * okhsl(240.5 50% 50%)\n * okhsl(240.5deg 50% 50%)\n * okhsl(0.25turn 50% 50%)\n * okhsl(1.57rad 50% 50%)\n *\n * Conversion math inlined from @texel/color to avoid external dependencies.\n */\n\nimport { Lru } from '../parser/lru';\n\nimport type { StyleDetails } from '../parser/types';\nimport type { TastyPlugin, TastyPluginFactory } from './types';\n\n// Cache for OKHSL to RGB conversions\nconst conversionCache = new Lru<string, string>(500);\n\n// ============================================================================\n// Conversion Matrices (from texel-color)\n// ============================================================================\n\nconst OKLab_to_LMS_M: [number, number, number][] = [\n [1.0, 0.3963377773761749, 0.2158037573099136],\n [1.0, -0.1055613458156586, -0.0638541728258133],\n [1.0, -0.0894841775298119, -1.2914855480194092],\n];\n\nconst LMS_to_linear_sRGB_M: [number, number, number][] = [\n [4.076741636075959, -3.307711539258062, 0.2309699031821041],\n [-1.2684379732850313, 2.6097573492876878, -0.3413193760026569],\n [-0.004196076138675526, -0.703418617935936, 1.7076146940746113],\n];\n\nconst OKLab_to_linear_sRGB_coefficients: [\n [[number, number], number[]],\n [[number, number], number[]],\n [[number, number], number[]],\n] = [\n [\n [-1.8817030993265873, -0.8093650129914302],\n [1.19086277, 1.76576728, 0.59662641, 0.75515197, 0.56771245],\n ],\n [\n [1.8144407988010998, -1.194452667805235],\n [0.73956515, -0.45954404, 0.08285427, 0.12541073, -0.14503204],\n ],\n [\n [0.13110757611180954, 1.813339709266608],\n [1.35733652, -0.00915799, -1.1513021, -0.50559606, 0.00692167],\n ],\n];\n\n// ============================================================================\n// Math Utilities\n// ============================================================================\n\nconst TAU = 2 * Math.PI;\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.max(Math.min(value, max), min);\n\nconst constrainAngle = (angle: number): number => ((angle % 360) + 360) % 360;\n\nconst copySign = (to: number, from: number): number =>\n Math.sign(to) === Math.sign(from) ? to : -to;\n\nconst _spow = (base: number, exp: number): number =>\n copySign(Math.abs(base) ** exp, base);\n\n// ============================================================================\n// sRGB Gamma Conversion\n// ============================================================================\n\nconst sRGBLinearToGamma = (val: number): number => {\n const sign = val < 0 ? -1 : 1;\n const abs = Math.abs(val);\n return abs > 0.0031308\n ? sign * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055)\n : 12.92 * val;\n};\n\n// ============================================================================\n// Matrix Operations\n// ============================================================================\n\ntype Vec3 = [number, number, number];\n\nconst dot3 = (a: Vec3, b: Vec3): number =>\n a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n\nconst transform = (input: Vec3, matrix: Vec3[]): Vec3 => [\n dot3(input, matrix[0]),\n dot3(input, matrix[1]),\n dot3(input, matrix[2]),\n];\n\nconst cubed3 = (lms: Vec3): Vec3 => [\n lms[0] * lms[0] * lms[0],\n lms[1] * lms[1] * lms[1],\n lms[2] * lms[2] * lms[2],\n];\n\n// ============================================================================\n// OKLab Conversion\n// ============================================================================\n\nconst OKLabToLinearSRGB = (lab: Vec3): Vec3 => {\n const lms = transform(lab, OKLab_to_LMS_M);\n const cubedLms = cubed3(lms);\n return transform(cubedLms, LMS_to_linear_sRGB_M);\n};\n\n// ============================================================================\n// OKHSL to OKLab Conversion (from texel-color)\n// ============================================================================\n\nconst K1 = 0.206;\nconst K2 = 0.03;\nconst K3 = (1.0 + K1) / (1.0 + K2);\n\nconst _toe = (x: number): number =>\n 0.5 *\n (K3 * x - K1 + Math.sqrt((K3 * x - K1) * (K3 * x - K1) + 4 * K2 * K3 * x));\n\nconst toeInv = (x: number): number => (x ** 2 + K1 * x) / (K3 * (x + K2));\n\nconst dotXY = (a: [number, number], b: [number, number]): number =>\n a[0] * b[0] + a[1] * b[1];\n\nconst computeMaxSaturationOKLC = (a: number, b: number): number => {\n const okCoeff = OKLab_to_linear_sRGB_coefficients;\n const lmsToRgb = LMS_to_linear_sRGB_M;\n const tmp2: [number, number] = [a, b];\n const tmp3: Vec3 = [0, a, b];\n\n let chnlCoeff: number[];\n let chnlLMS: Vec3;\n\n if (dotXY(okCoeff[0][0], tmp2) > 1) {\n chnlCoeff = okCoeff[0][1];\n chnlLMS = lmsToRgb[0];\n } else if (dotXY(okCoeff[1][0], tmp2) > 1) {\n chnlCoeff = okCoeff[1][1];\n chnlLMS = lmsToRgb[1];\n } else {\n chnlCoeff = okCoeff[2][1];\n chnlLMS = lmsToRgb[2];\n }\n\n const [k0, k1, k2, k3, k4] = chnlCoeff;\n const [wl, wm, ws] = chnlLMS;\n\n let sat = k0 + k1 * a + k2 * b + k3 * (a * a) + k4 * a * b;\n\n const dotYZ = (mat: Vec3, vec: Vec3): number =>\n mat[1] * vec[1] + mat[2] * vec[2];\n\n const kl = dotYZ(OKLab_to_LMS_M[0], tmp3);\n const km = dotYZ(OKLab_to_LMS_M[1], tmp3);\n const ks = dotYZ(OKLab_to_LMS_M[2], tmp3);\n\n const l_ = 1.0 + sat * kl;\n const m_ = 1.0 + sat * km;\n const s_ = 1.0 + sat * ks;\n\n const l = l_ * l_ * l_;\n const m = m_ * m_ * m_;\n const s = s_ * s_ * s_;\n\n const lds = 3.0 * kl * (l_ * l_);\n const mds = 3.0 * km * (m_ * m_);\n const sds = 3.0 * ks * (s_ * s_);\n\n const lds2 = 6.0 * (kl * kl) * l_;\n const mds2 = 6.0 * (km * km) * m_;\n const sds2 = 6.0 * (ks * ks) * s_;\n\n const f = wl * l + wm * m + ws * s;\n const f1 = wl * lds + wm * mds + ws * sds;\n const f2 = wl * lds2 + wm * mds2 + ws * sds2;\n\n sat = sat - (f * f1) / (f1 * f1 - 0.5 * f * f2);\n\n return sat;\n};\n\nconst findCuspOKLCH = (a: number, b: number): [number, number] => {\n const _lmsToRgb = LMS_to_linear_sRGB_M;\n const S_cusp = computeMaxSaturationOKLC(a, b);\n\n const lab: Vec3 = [1, S_cusp * a, S_cusp * b];\n const rgb_at_max = OKLabToLinearSRGB(lab);\n\n const L_cusp = Math.cbrt(\n 1 /\n Math.max(\n Math.max(rgb_at_max[0], rgb_at_max[1]),\n Math.max(rgb_at_max[2], 0.0),\n ),\n );\n const C_cusp = L_cusp * S_cusp;\n\n return [L_cusp, C_cusp];\n};\n\nconst findGamutIntersectionOKLCH = (\n a: number,\n b: number,\n l1: number,\n c1: number,\n l0: number,\n cusp: [number, number],\n): number => {\n const lmsToRgb = LMS_to_linear_sRGB_M;\n const tmp3: Vec3 = [0, a, b];\n const floatMax = Number.MAX_VALUE;\n\n let t: number;\n\n const dotYZ = (mat: Vec3, vec: Vec3): number =>\n mat[1] * vec[1] + mat[2] * vec[2];\n const dotXYZ = (vec: Vec3, x: number, y: number, z: number): number =>\n vec[0] * x + vec[1] * y + vec[2] * z;\n\n if ((l1 - l0) * cusp[1] - (cusp[0] - l0) * c1 <= 0.0) {\n const denom = c1 * cusp[0] + cusp[1] * (l0 - l1);\n t = denom === 0 ? 0 : (cusp[1] * l0) / denom;\n } else {\n const denom = c1 * (cusp[0] - 1.0) + cusp[1] * (l0 - l1);\n t = denom === 0 ? 0 : (cusp[1] * (l0 - 1.0)) / denom;\n\n const dl = l1 - l0;\n const dc = c1;\n\n const kl = dotYZ(OKLab_to_LMS_M[0], tmp3);\n const km = dotYZ(OKLab_to_LMS_M[1], tmp3);\n const ks = dotYZ(OKLab_to_LMS_M[2], tmp3);\n\n const ldt_ = dl + dc * kl;\n const mdt_ = dl + dc * km;\n const sdt_ = dl + dc * ks;\n\n const L = l0 * (1.0 - t) + t * l1;\n const C = t * c1;\n\n const l_ = L + C * kl;\n const m_ = L + C * km;\n const s_ = L + C * ks;\n\n const l = l_ * l_ * l_;\n const m = m_ * m_ * m_;\n const s = s_ * s_ * s_;\n\n const ldt = 3 * ldt_ * l_ * l_;\n const mdt = 3 * mdt_ * m_ * m_;\n const sdt = 3 * sdt_ * s_ * s_;\n\n const ldt2 = 6 * ldt_ * ldt_ * l_;\n const mdt2 = 6 * mdt_ * mdt_ * m_;\n const sdt2 = 6 * sdt_ * sdt_ * s_;\n\n const r_ = dotXYZ(lmsToRgb[0], l, m, s) - 1;\n const r1 = dotXYZ(lmsToRgb[0], ldt, mdt, sdt);\n const r2 = dotXYZ(lmsToRgb[0], ldt2, mdt2, sdt2);\n\n const ur = r1 / (r1 * r1 - 0.5 * r_ * r2);\n let tr = -r_ * ur;\n\n const g_ = dotXYZ(lmsToRgb[1], l, m, s) - 1;\n const g1 = dotXYZ(lmsToRgb[1], ldt, mdt, sdt);\n const g2 = dotXYZ(lmsToRgb[1], ldt2, mdt2, sdt2);\n\n const ug = g1 / (g1 * g1 - 0.5 * g_ * g2);\n let tg = -g_ * ug;\n\n const b_ = dotXYZ(lmsToRgb[2], l, m, s) - 1;\n const b1 = dotXYZ(lmsToRgb[2], ldt, mdt, sdt);\n const b2 = dotXYZ(lmsToRgb[2], ldt2, mdt2, sdt2);\n\n const ub = b1 / (b1 * b1 - 0.5 * b_ * b2);\n let tb = -b_ * ub;\n\n tr = ur >= 0.0 ? tr : floatMax;\n tg = ug >= 0.0 ? tg : floatMax;\n tb = ub >= 0.0 ? tb : floatMax;\n\n t += Math.min(tr, Math.min(tg, tb));\n }\n\n return t;\n};\n\nconst computeSt = (cusp: [number, number]): [number, number] => {\n const l = cusp[0];\n const c = cusp[1];\n return [c / l, c / (1 - l)];\n};\n\nconst computeStMid = (a: number, b: number): [number, number] => {\n const s =\n 0.11516993 +\n 1.0 /\n (7.4477897 +\n 4.1590124 * b +\n a *\n (-2.19557347 +\n 1.75198401 * b +\n a *\n (-2.13704948 -\n 10.02301043 * b +\n a * (-4.24894561 + 5.38770819 * b + 4.69891013 * a))));\n\n const t =\n 0.11239642 +\n 1.0 /\n (1.6132032 -\n 0.68124379 * b +\n a *\n (0.40370612 +\n 0.90148123 * b +\n a *\n (-0.27087943 +\n 0.6122399 * b +\n a * (0.00299215 - 0.45399568 * b - 0.14661872 * a))));\n\n return [s, t];\n};\n\nconst getCs = (\n L: number,\n a: number,\n b: number,\n cusp: [number, number],\n): [number, number, number] => {\n const cMax = findGamutIntersectionOKLCH(a, b, L, 1, L, cusp);\n const stMax = computeSt(cusp);\n\n const k = cMax / Math.min(L * stMax[0], (1 - L) * stMax[1]);\n\n const stMid = computeStMid(a, b);\n\n let ca = L * stMid[0];\n let cb = (1.0 - L) * stMid[1];\n const cMid =\n 0.9 * k * Math.sqrt(Math.sqrt(1.0 / (1.0 / ca ** 4 + 1.0 / cb ** 4)));\n\n ca = L * 0.4;\n cb = (1.0 - L) * 0.8;\n const c0 = Math.sqrt(1.0 / (1.0 / ca ** 2 + 1.0 / cb ** 2));\n\n return [c0, cMid, cMax];\n};\n\nconst OKHSLToOKLab = (hsl: Vec3): Vec3 => {\n let h = hsl[0];\n const s = hsl[1];\n const l = hsl[2];\n\n const L = toeInv(l);\n let a = 0;\n let b = 0;\n\n h = constrainAngle(h) / 360.0;\n\n if (L !== 0.0 && L !== 1.0 && s !== 0) {\n const a_ = Math.cos(TAU * h);\n const b_ = Math.sin(TAU * h);\n\n const cusp = findCuspOKLCH(a_, b_);\n const Cs = getCs(L, a_, b_, cusp);\n const [c0, cMid, cMax] = Cs;\n\n const mid = 0.8;\n const midInv = 1.25;\n let t: number, k0: number, k1: number, k2: number;\n\n if (s < mid) {\n t = midInv * s;\n k0 = 0.0;\n k1 = mid * c0;\n k2 = 1.0 - k1 / cMid;\n } else {\n t = 5 * (s - 0.8);\n k0 = cMid;\n k1 = (0.2 * cMid ** 2 * 1.25 ** 2) / c0;\n k2 = 1.0 - k1 / (cMax - cMid);\n }\n\n const c = k0 + (t * k1) / (1.0 - k2 * t);\n\n a = c * a_;\n b = c * b_;\n }\n\n return [L, a, b];\n};\n\n// ============================================================================\n// OKHSL to sRGB Conversion\n// ============================================================================\n\nconst okhslToSRGB = (h: number, s: number, l: number): Vec3 => {\n // h: 0-360, s: 0-1, l: 0-1\n const oklab = OKHSLToOKLab([h, s, l]);\n const linearRGB = OKLabToLinearSRGB(oklab);\n\n // Apply gamma correction and clamp\n return [\n clamp(sRGBLinearToGamma(linearRGB[0]), 0, 1),\n clamp(sRGBLinearToGamma(linearRGB[1]), 0, 1),\n clamp(sRGBLinearToGamma(linearRGB[2]), 0, 1),\n ];\n};\n\n// ============================================================================\n// Parsing Utilities\n// ============================================================================\n\n/**\n * Parse an angle value with optional unit.\n * Supports: deg, turn, rad, or unitless (treated as degrees).\n */\nconst parseAngle = (value: string): number => {\n const match = value.match(/^([+-]?\\d*\\.?\\d+)(deg|turn|rad)?$/);\n if (!match) return 0;\n\n const num = parseFloat(match[1]);\n const unit = match[2];\n\n switch (unit) {\n case 'turn':\n return num * 360;\n case 'rad':\n return (num * 180) / Math.PI;\n case 'deg':\n default:\n return num;\n }\n};\n\n/**\n * Parse a percentage value (e.g., \"50%\") to a 0-1 range.\n */\nconst parsePercentage = (value: string): number => {\n const match = value.match(/^([+-]?\\d*\\.?\\d+)%?$/);\n if (!match) return 0;\n\n const num = parseFloat(match[1]);\n // If the value includes %, divide by 100, otherwise assume 0-1 range\n return value.includes('%') ? num / 100 : num;\n};\n\n// ============================================================================\n// Plugin Implementation\n// ============================================================================\n\n/**\n * The okhsl function handler for tasty parser.\n * Receives parsed style groups and returns an RGB color string.\n */\nconst okhslFunc = (groups: StyleDetails[]): string => {\n // We expect a single group with 3 values: H, S, L\n // and an optional slash-separated alpha part\n if (groups.length === 0 || groups[0].all.length < 3) {\n console.warn('[okhsl] Expected 3 values (H S L), got:', groups);\n return 'rgb(0% 0% 0%)';\n }\n\n const group = groups[0];\n const tokens = group.all;\n\n // Alpha is in the second slash-separated part (e.g., okhsl(240 50% 50% / .5))\n const alpha =\n group.parts.length > 1 && group.parts[1].all.length > 0\n ? group.parts[1].output\n : undefined;\n\n // Create cache key from input tokens\n const cacheKey = tokens.slice(0, 3).join(' ') + (alpha ? ` / ${alpha}` : '');\n const cached = conversionCache.get(cacheKey);\n if (cached) return cached;\n\n const h = parseAngle(tokens[0]);\n const s = parsePercentage(tokens[1]);\n const l = parsePercentage(tokens[2]);\n\n const [r, g, b] = okhslToSRGB(h, clamp(s, 0, 1), clamp(l, 0, 1));\n\n const format = (n: number): string => {\n const pct = n * 100;\n return parseFloat(pct.toFixed(1)).toString() + '%';\n };\n\n const result = alpha\n ? `rgb(${format(r)} ${format(g)} ${format(b)} / ${alpha})`\n : `rgb(${format(r)} ${format(g)} ${format(b)})`;\n\n conversionCache.set(cacheKey, result);\n return result;\n};\n\n/**\n * OKHSL Plugin for Tasty.\n *\n * Adds support for the `okhsl()` color function in tasty styles.\n *\n * @example\n * ```ts\n * import { configure } from '@tenphi/tasty';\n * import { okhslPlugin } from '@tenphi/tasty';\n *\n * configure({\n * plugins: [okhslPlugin()],\n * });\n *\n * // Now you can use okhsl in styles:\n * const Box = tasty({\n * styles: {\n * fill: 'okhsl(240 50% 50%)',\n * },\n * });\n * ```\n */\nexport const okhslPlugin: TastyPluginFactory = (): TastyPlugin => ({\n name: 'okhsl',\n funcs: {\n okhsl: okhslFunc,\n },\n});\n\n// Export the raw function for direct use if needed\nexport { okhslFunc };\n"],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { StyleDetails, UnitHandler } from "../parser/types.mjs";
2
+ import { StyleHandlerDefinition } from "../utils/styles.mjs";
3
+ import { RecipeStyles } from "../styles/types.mjs";
4
+
5
+ //#region src/plugins/types.d.ts
6
+ /**
7
+ * A tasty plugin that extends the style system with custom functions, units, states, or handlers.
8
+ */
9
+ interface TastyPlugin {
10
+ /** Unique name for the plugin (used for debugging and conflict detection) */
11
+ name: string;
12
+ /** Custom functions that transform parsed style groups into CSS values */
13
+ funcs?: Record<string, (groups: StyleDetails[]) => string>;
14
+ /** Custom units that transform numeric values (e.g., `2x` → `calc(2 * var(--gap))`) */
15
+ units?: Record<string, string | UnitHandler>;
16
+ /** Custom state aliases (e.g., `'@mobile': '@media(w < 768px)'`) */
17
+ states?: Record<string, string>;
18
+ /**
19
+ * Custom style handlers that transform style properties into CSS declarations.
20
+ * Handlers replace built-in handlers for the same style name.
21
+ * @example
22
+ * ```ts
23
+ * handlers: {
24
+ * // Simple handler - lookup style inferred from key
25
+ * fill: ({ fill }) => fill ? { 'background-color': fill } : undefined,
26
+ * // Multi-property handler
27
+ * spacing: [['gap', 'padding'], ({ gap, padding }) => ({ ... })],
28
+ * }
29
+ * ```
30
+ */
31
+ handlers?: Record<string, StyleHandlerDefinition>;
32
+ /** Predefined tokens replaced during style parsing (`$name` or `#name`) */
33
+ tokens?: Record<`$${string}` | `#${string}`, string | number>;
34
+ /**
35
+ * Predefined style recipes -- named style bundles that can be applied via `recipe` style property.
36
+ * Recipe values are flat tasty styles (no sub-element keys).
37
+ * @example
38
+ * ```ts
39
+ * recipes: {
40
+ * card: { padding: '4x', fill: '#surface', radius: '1r', border: true },
41
+ * elevated: { shadow: '2x 2x 4x #shadow' },
42
+ * }
43
+ * ```
44
+ */
45
+ recipes?: Record<string, RecipeStyles>;
46
+ }
47
+ //#endregion
48
+ export { TastyPlugin };
49
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1,69 @@
1
+ import { StyleDetails, UnitHandler } from "../parser/types.js";
2
+ import { StyleHandlerDefinition } from "../utils/styles.js";
3
+ import { RecipeStyles } from "../styles/types.js";
4
+
5
+ //#region src/plugins/types.d.ts
6
+ /**
7
+ * A tasty plugin that extends the style system with custom functions, units, states, or handlers.
8
+ */
9
+ interface TastyPlugin {
10
+ /** Unique name for the plugin (used for debugging and conflict detection) */
11
+ name: string;
12
+ /** Custom functions that transform parsed style groups into CSS values */
13
+ funcs?: Record<string, (groups: StyleDetails[]) => string>;
14
+ /** Custom units that transform numeric values (e.g., `2x` → `calc(2 * var(--gap))`) */
15
+ units?: Record<string, string | UnitHandler>;
16
+ /** Custom state aliases (e.g., `'@mobile': '@media(w < 768px)'`) */
17
+ states?: Record<string, string>;
18
+ /**
19
+ * Custom style handlers that transform style properties into CSS declarations.
20
+ * Handlers replace built-in handlers for the same style name.
21
+ * @example
22
+ * ```ts
23
+ * handlers: {
24
+ * // Simple handler - lookup style inferred from key
25
+ * fill: ({ fill }) => fill ? { 'background-color': fill } : undefined,
26
+ * // Multi-property handler
27
+ * spacing: [['gap', 'padding'], ({ gap, padding }) => ({ ... })],
28
+ * }
29
+ * ```
30
+ */
31
+ handlers?: Record<string, StyleHandlerDefinition>;
32
+ /** Predefined tokens replaced during style parsing (`$name` or `#name`) */
33
+ tokens?: Record<`$${string}` | `#${string}`, string | number>;
34
+ /**
35
+ * Predefined style recipes -- named style bundles that can be applied via `recipe` style property.
36
+ * Recipe values are flat tasty styles (no sub-element keys).
37
+ * @example
38
+ * ```ts
39
+ * recipes: {
40
+ * card: { padding: '4x', fill: '#surface', radius: '1r', border: true },
41
+ * elevated: { shadow: '2x 2x 4x #shadow' },
42
+ * }
43
+ * ```
44
+ */
45
+ recipes?: Record<string, RecipeStyles>;
46
+ }
47
+ /**
48
+ * A factory function that creates a TastyPlugin.
49
+ * Can optionally accept configuration options.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * // Plugin without options
54
+ * const okhslPlugin: TastyPluginFactory = () => ({
55
+ * name: 'okhsl',
56
+ * funcs: { okhsl: okhslFunc },
57
+ * });
58
+ *
59
+ * // Plugin with options
60
+ * const debugPlugin: TastyPluginFactory<{ verbose: boolean }> = (options) => ({
61
+ * name: 'debug',
62
+ * funcs: { debug: createDebugFunc(options.verbose) },
63
+ * });
64
+ * ```
65
+ */
66
+ type TastyPluginFactory<TOptions = void> = TOptions extends void ? () => TastyPlugin : (options: TOptions) => TastyPlugin;
67
+ //#endregion
68
+ export { TastyPlugin, TastyPluginFactory };
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,158 @@
1
+ import { getRgbValuesFromRgbaString, strToRgb } from "../utils/styles.js";
2
+
3
+ //#region src/properties/index.ts
4
+ const PROPERTIES_KEY = "@properties";
5
+ /**
6
+ * Valid CSS custom property name pattern (after the -- prefix).
7
+ * Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.
8
+ */
9
+ const VALID_PROPERTY_NAME_PATTERN = /^[a-z_][a-z0-9-_]*$/i;
10
+ /**
11
+ * Validate a CSS custom property name (the part after --).
12
+ * Returns true if the name is valid for use as a CSS custom property.
13
+ */
14
+ function isValidPropertyName(name) {
15
+ return VALID_PROPERTY_NAME_PATTERN.test(name);
16
+ }
17
+ /**
18
+ * Check if styles object has local @properties definition.
19
+ * Fast path: single property lookup.
20
+ */
21
+ function hasLocalProperties(styles) {
22
+ return PROPERTIES_KEY in styles;
23
+ }
24
+ /**
25
+ * Extract local @properties from styles object.
26
+ * Returns null if no local properties (fast path).
27
+ */
28
+ function extractLocalProperties(styles) {
29
+ const properties = styles[PROPERTIES_KEY];
30
+ if (!properties || typeof properties !== "object") return null;
31
+ return properties;
32
+ }
33
+ /**
34
+ * Parse a property token name and return the CSS property name and whether it's a color.
35
+ * Supports tasty token syntax and validates the property name.
36
+ *
37
+ * Token formats:
38
+ * - `$name` → { cssName: '--name', isColor: false }
39
+ * - `#name` → { cssName: '--name-color', isColor: true }
40
+ * - `--name` → { cssName: '--name', isColor: false } (legacy, auto-detect color by suffix)
41
+ * - `name` → { cssName: '--name', isColor: false } (legacy)
42
+ *
43
+ * @param token - The property token to parse
44
+ * @returns Parsed result with cssName, isColor, isValid, and optional error
45
+ */
46
+ function parsePropertyToken(token) {
47
+ if (!token || typeof token !== "string") return {
48
+ cssName: "",
49
+ isColor: false,
50
+ isValid: false,
51
+ error: "Property token must be a non-empty string"
52
+ };
53
+ let name;
54
+ let isColor;
55
+ if (token.startsWith("$")) {
56
+ name = token.slice(1);
57
+ isColor = false;
58
+ } else if (token.startsWith("#")) {
59
+ name = token.slice(1);
60
+ isColor = true;
61
+ } else if (token.startsWith("--")) {
62
+ name = token.slice(2);
63
+ isColor = token.endsWith("-color");
64
+ } else {
65
+ name = token;
66
+ isColor = token.endsWith("-color");
67
+ }
68
+ if (!name) return {
69
+ cssName: "",
70
+ isColor,
71
+ isValid: false,
72
+ error: "Property name cannot be empty"
73
+ };
74
+ if (!isValidPropertyName(name)) return {
75
+ cssName: "",
76
+ isColor,
77
+ isValid: false,
78
+ error: `Invalid property name "${name}". Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.`
79
+ };
80
+ let cssName;
81
+ if (token.startsWith("#")) cssName = `--${name}-color`;
82
+ else cssName = `--${name}`;
83
+ return {
84
+ cssName,
85
+ isColor,
86
+ isValid: true
87
+ };
88
+ }
89
+ /**
90
+ * Normalize a property definition to a consistent string representation.
91
+ * Used for comparing definitions to detect changes/conflicts.
92
+ *
93
+ * Keys are sorted alphabetically to ensure consistent comparison:
94
+ * { inherits: true, syntax: '<color>' } === { syntax: '<color>', inherits: true }
95
+ */
96
+ function normalizePropertyDefinition(def) {
97
+ const normalized = {};
98
+ if (def.inherits !== void 0) normalized.inherits = def.inherits;
99
+ if (def.initialValue !== void 0) normalized.initialValue = String(def.initialValue);
100
+ if (def.syntax !== void 0) normalized.syntax = def.syntax;
101
+ return JSON.stringify(normalized);
102
+ }
103
+ /**
104
+ * Get the effective property definition for a token.
105
+ * For color tokens (#name), auto-sets syntax to '<color>' and defaults initialValue to 'transparent'.
106
+ *
107
+ * @param token - Property token ($name, #name, --name, or plain name)
108
+ * @param userDefinition - User-provided definition options
109
+ * @returns Effective definition with cssName, definition, isValid, and optional error
110
+ */
111
+ function getEffectiveDefinition(token, userDefinition) {
112
+ const parsed = parsePropertyToken(token);
113
+ if (!parsed.isValid) return {
114
+ cssName: "",
115
+ definition: userDefinition,
116
+ isColor: false,
117
+ isValid: false,
118
+ error: parsed.error
119
+ };
120
+ if (parsed.isColor) return {
121
+ cssName: parsed.cssName,
122
+ definition: {
123
+ syntax: "<color>",
124
+ inherits: userDefinition.inherits,
125
+ initialValue: userDefinition.initialValue ?? "transparent"
126
+ },
127
+ isColor: true,
128
+ isValid: true
129
+ };
130
+ return {
131
+ cssName: parsed.cssName,
132
+ definition: userDefinition,
133
+ isColor: false,
134
+ isValid: true
135
+ };
136
+ }
137
+ /**
138
+ * Extract RGB triplet string from a color initial value.
139
+ * Used when auto-creating the companion `-rgb` property for color @property definitions.
140
+ *
141
+ * @param initialValue - The color property's initial value (e.g., 'rgb(255 255 255)', 'transparent', '#fff')
142
+ * @returns Space-separated RGB triplet (e.g., '255 255 255'), defaults to '0 0 0'
143
+ */
144
+ function colorInitialValueToRgb(initialValue) {
145
+ if (initialValue == null) return "0 0 0";
146
+ const str = String(initialValue).trim();
147
+ if (!str || str === "transparent") return "0 0 0";
148
+ const rgba = strToRgb(str);
149
+ if (rgba) {
150
+ const values = getRgbValuesFromRgbaString(rgba);
151
+ if (values.length >= 3) return values.slice(0, 3).join(" ");
152
+ }
153
+ return "0 0 0";
154
+ }
155
+
156
+ //#endregion
157
+ export { colorInitialValueToRgb, extractLocalProperties, getEffectiveDefinition, hasLocalProperties, normalizePropertyDefinition };
158
+ //# sourceMappingURL=index.js.map