@just-web/toolkits 1.0.0 → 2.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 (421) hide show
  1. package/dist/attributes/get-attribute.cjs +1 -1
  2. package/dist/attributes/get-attribute.cjs.map +1 -1
  3. package/dist/attributes/get-attribute.d.cts +2 -2
  4. package/dist/attributes/get-attribute.d.cts.map +1 -1
  5. package/dist/attributes/get-attribute.d.mts +2 -2
  6. package/dist/attributes/get-attribute.d.mts.map +1 -1
  7. package/dist/attributes/get-attribute.mjs +1 -1
  8. package/dist/attributes/get-attribute.mjs.map +1 -1
  9. package/dist/attributes/get-data-attribute.cjs +1 -1
  10. package/dist/attributes/get-data-attribute.cjs.map +1 -1
  11. package/dist/attributes/get-data-attribute.d.cts +2 -2
  12. package/dist/attributes/get-data-attribute.d.cts.map +1 -1
  13. package/dist/attributes/get-data-attribute.d.mts +2 -2
  14. package/dist/attributes/get-data-attribute.d.mts.map +1 -1
  15. package/dist/attributes/get-data-attribute.mjs +1 -1
  16. package/dist/attributes/get-data-attribute.mjs.map +1 -1
  17. package/dist/attributes/observe-attribute.cjs +1 -1
  18. package/dist/attributes/observe-attribute.cjs.map +1 -1
  19. package/dist/attributes/observe-attribute.d.cts +2 -2
  20. package/dist/attributes/observe-attribute.d.cts.map +1 -1
  21. package/dist/attributes/observe-attribute.d.mts +2 -2
  22. package/dist/attributes/observe-attribute.d.mts.map +1 -1
  23. package/dist/attributes/observe-attribute.mjs +1 -1
  24. package/dist/attributes/observe-attribute.mjs.map +1 -1
  25. package/dist/attributes/observe-data-attribute.cjs +1 -1
  26. package/dist/attributes/observe-data-attribute.cjs.map +1 -1
  27. package/dist/attributes/observe-data-attribute.d.cts +2 -2
  28. package/dist/attributes/observe-data-attribute.d.cts.map +1 -1
  29. package/dist/attributes/observe-data-attribute.d.mts +2 -2
  30. package/dist/attributes/observe-data-attribute.d.mts.map +1 -1
  31. package/dist/attributes/observe-data-attribute.mjs +1 -1
  32. package/dist/attributes/observe-data-attribute.mjs.map +1 -1
  33. package/dist/color-scheme/color-scheme.types.d.cts +11 -0
  34. package/dist/color-scheme/color-scheme.types.d.cts.map +1 -0
  35. package/dist/color-scheme/color-scheme.types.d.mts +11 -0
  36. package/dist/color-scheme/color-scheme.types.d.mts.map +1 -0
  37. package/dist/color-scheme/get-prefers-color-scheme.cjs +3 -1
  38. package/dist/color-scheme/get-prefers-color-scheme.cjs.map +1 -1
  39. package/dist/color-scheme/get-prefers-color-scheme.d.cts +7 -2
  40. package/dist/color-scheme/get-prefers-color-scheme.d.cts.map +1 -1
  41. package/dist/color-scheme/get-prefers-color-scheme.d.mts +7 -2
  42. package/dist/color-scheme/get-prefers-color-scheme.d.mts.map +1 -1
  43. package/dist/color-scheme/get-prefers-color-scheme.mjs +3 -1
  44. package/dist/color-scheme/get-prefers-color-scheme.mjs.map +1 -1
  45. package/dist/color-scheme/observe-prefers-color-scheme.cjs.map +1 -1
  46. package/dist/color-scheme/observe-prefers-color-scheme.d.cts +4 -1
  47. package/dist/color-scheme/observe-prefers-color-scheme.d.cts.map +1 -1
  48. package/dist/color-scheme/observe-prefers-color-scheme.d.mts +4 -1
  49. package/dist/color-scheme/observe-prefers-color-scheme.d.mts.map +1 -1
  50. package/dist/color-scheme/observe-prefers-color-scheme.mjs.map +1 -1
  51. package/dist/index.d.cts +2 -1
  52. package/dist/index.d.mts +2 -1
  53. package/dist/react/hooks/use-attribute.cjs +7 -7
  54. package/dist/react/hooks/use-attribute.cjs.map +1 -1
  55. package/dist/react/hooks/use-attribute.d.cts +4 -4
  56. package/dist/react/hooks/use-attribute.d.mts +4 -4
  57. package/dist/react/hooks/use-attribute.mjs +7 -7
  58. package/dist/react/hooks/use-attribute.mjs.map +1 -1
  59. package/dist/react/hooks/use-theme-by-class-name.cjs +2 -6
  60. package/dist/react/hooks/use-theme-by-class-name.cjs.map +1 -1
  61. package/dist/react/hooks/use-theme-by-class-name.d.cts +2 -2
  62. package/dist/react/hooks/use-theme-by-class-name.d.cts.map +1 -1
  63. package/dist/react/hooks/use-theme-by-class-name.d.mts +2 -2
  64. package/dist/react/hooks/use-theme-by-class-name.d.mts.map +1 -1
  65. package/dist/react/hooks/use-theme-by-class-name.mjs +2 -6
  66. package/dist/react/hooks/use-theme-by-class-name.mjs.map +1 -1
  67. package/dist/react/hooks/use-theme-by-data-attribute.cjs +2 -7
  68. package/dist/react/hooks/use-theme-by-data-attribute.cjs.map +1 -1
  69. package/dist/react/hooks/use-theme-by-data-attribute.d.cts +2 -2
  70. package/dist/react/hooks/use-theme-by-data-attribute.d.cts.map +1 -1
  71. package/dist/react/hooks/use-theme-by-data-attribute.d.mts +2 -2
  72. package/dist/react/hooks/use-theme-by-data-attribute.d.mts.map +1 -1
  73. package/dist/react/hooks/use-theme-by-data-attribute.mjs +2 -7
  74. package/dist/react/hooks/use-theme-by-data-attribute.mjs.map +1 -1
  75. package/dist/react/hooks/use-theme-by-local-storage.cjs +1 -5
  76. package/dist/react/hooks/use-theme-by-local-storage.cjs.map +1 -1
  77. package/dist/react/hooks/use-theme-by-local-storage.d.cts.map +1 -1
  78. package/dist/react/hooks/use-theme-by-local-storage.d.mts.map +1 -1
  79. package/dist/react/hooks/use-theme-by-local-storage.mjs +1 -5
  80. package/dist/react/hooks/use-theme-by-local-storage.mjs.map +1 -1
  81. package/dist/react/theme/create-theme-hook.cjs.map +1 -1
  82. package/dist/react/theme/create-theme-hook.mjs.map +1 -1
  83. package/dist/theme/_utils/match-attribute-value-to-theme.cjs +29 -0
  84. package/dist/theme/_utils/match-attribute-value-to-theme.cjs.map +1 -0
  85. package/dist/theme/_utils/match-attribute-value-to-theme.mjs +28 -0
  86. package/dist/theme/_utils/match-attribute-value-to-theme.mjs.map +1 -0
  87. package/dist/theme/_utils/parse-stored-theme.cjs +61 -7
  88. package/dist/theme/_utils/parse-stored-theme.cjs.map +1 -1
  89. package/dist/theme/_utils/parse-stored-theme.mjs +61 -7
  90. package/dist/theme/_utils/parse-stored-theme.mjs.map +1 -1
  91. package/dist/theme/_utils/resolve-theme-map-value.cjs +19 -0
  92. package/dist/theme/_utils/resolve-theme-map-value.cjs.map +1 -0
  93. package/dist/theme/_utils/resolve-theme-map-value.mjs +17 -0
  94. package/dist/theme/_utils/resolve-theme-map-value.mjs.map +1 -0
  95. package/dist/theme/_utils/set-theme-to-stores.cjs +1 -1
  96. package/dist/theme/_utils/set-theme-to-stores.cjs.map +1 -1
  97. package/dist/theme/_utils/set-theme-to-stores.mjs +1 -1
  98. package/dist/theme/_utils/set-theme-to-stores.mjs.map +1 -1
  99. package/dist/theme/class-name/parse-class-name.cjs +32 -0
  100. package/dist/theme/class-name/parse-class-name.cjs.map +1 -0
  101. package/dist/theme/class-name/parse-class-name.d.cts +20 -0
  102. package/dist/theme/class-name/parse-class-name.d.cts.map +1 -0
  103. package/dist/theme/class-name/parse-class-name.d.mts +20 -0
  104. package/dist/theme/class-name/parse-class-name.d.mts.map +1 -0
  105. package/dist/theme/class-name/parse-class-name.mjs +31 -0
  106. package/dist/theme/class-name/parse-class-name.mjs.map +1 -0
  107. package/dist/theme/class-name/read-class-name.cjs +20 -0
  108. package/dist/theme/class-name/read-class-name.cjs.map +1 -0
  109. package/dist/theme/class-name/read-class-name.d.cts +20 -0
  110. package/dist/theme/class-name/read-class-name.d.cts.map +1 -0
  111. package/dist/theme/class-name/read-class-name.d.mts +20 -0
  112. package/dist/theme/class-name/read-class-name.d.mts.map +1 -0
  113. package/dist/theme/class-name/read-class-name.mjs +20 -0
  114. package/dist/theme/class-name/read-class-name.mjs.map +1 -0
  115. package/dist/theme/class-name/stringify-class-name.cjs +31 -0
  116. package/dist/theme/class-name/stringify-class-name.cjs.map +1 -0
  117. package/dist/theme/class-name/stringify-class-name.d.cts +21 -0
  118. package/dist/theme/class-name/stringify-class-name.d.cts.map +1 -0
  119. package/dist/theme/class-name/stringify-class-name.d.mts +21 -0
  120. package/dist/theme/class-name/stringify-class-name.d.mts.map +1 -0
  121. package/dist/theme/class-name/stringify-class-name.mjs +31 -0
  122. package/dist/theme/class-name/stringify-class-name.mjs.map +1 -0
  123. package/dist/theme/class-name/subscribe-class-name.cjs +31 -0
  124. package/dist/theme/class-name/subscribe-class-name.cjs.map +1 -0
  125. package/dist/theme/class-name/subscribe-class-name.d.cts +21 -0
  126. package/dist/theme/class-name/subscribe-class-name.d.cts.map +1 -0
  127. package/dist/theme/class-name/subscribe-class-name.d.mts +21 -0
  128. package/dist/theme/class-name/subscribe-class-name.d.mts.map +1 -0
  129. package/dist/theme/class-name/subscribe-class-name.mjs +31 -0
  130. package/dist/theme/class-name/subscribe-class-name.mjs.map +1 -0
  131. package/dist/theme/class-name/write-class-name.cjs +20 -0
  132. package/dist/theme/class-name/write-class-name.cjs.map +1 -0
  133. package/dist/theme/class-name/write-class-name.d.cts +20 -0
  134. package/dist/theme/class-name/write-class-name.d.cts.map +1 -0
  135. package/dist/theme/class-name/write-class-name.d.mts +20 -0
  136. package/dist/theme/class-name/write-class-name.d.mts.map +1 -0
  137. package/dist/theme/class-name/write-class-name.mjs +20 -0
  138. package/dist/theme/class-name/write-class-name.mjs.map +1 -0
  139. package/dist/theme/compose-theme-stores.cjs.map +1 -1
  140. package/dist/theme/compose-theme-stores.mjs.map +1 -1
  141. package/dist/theme/cookie/_cookie-utils.cjs +37 -0
  142. package/dist/theme/cookie/_cookie-utils.cjs.map +1 -0
  143. package/dist/theme/cookie/_cookie-utils.mjs +33 -0
  144. package/dist/theme/cookie/_cookie-utils.mjs.map +1 -0
  145. package/dist/theme/cookie/read-cookie-theme.cjs +22 -0
  146. package/dist/theme/cookie/read-cookie-theme.cjs.map +1 -0
  147. package/dist/theme/cookie/read-cookie-theme.d.cts +22 -0
  148. package/dist/theme/cookie/read-cookie-theme.d.cts.map +1 -0
  149. package/dist/theme/cookie/read-cookie-theme.d.mts +22 -0
  150. package/dist/theme/cookie/read-cookie-theme.d.mts.map +1 -0
  151. package/dist/theme/cookie/read-cookie-theme.mjs +22 -0
  152. package/dist/theme/cookie/read-cookie-theme.mjs.map +1 -0
  153. package/dist/theme/cookie/write-cookie-theme.cjs +29 -0
  154. package/dist/theme/cookie/write-cookie-theme.cjs.map +1 -0
  155. package/dist/theme/cookie/write-cookie-theme.d.cts +24 -0
  156. package/dist/theme/cookie/write-cookie-theme.d.cts.map +1 -0
  157. package/dist/theme/cookie/write-cookie-theme.d.mts +24 -0
  158. package/dist/theme/cookie/write-cookie-theme.d.mts.map +1 -0
  159. package/dist/theme/cookie/write-cookie-theme.mjs +29 -0
  160. package/dist/theme/cookie/write-cookie-theme.mjs.map +1 -0
  161. package/dist/theme/data-attribute/_constant.cjs +7 -0
  162. package/dist/theme/data-attribute/_constant.cjs.map +1 -0
  163. package/dist/theme/data-attribute/_constant.mjs +6 -0
  164. package/dist/theme/data-attribute/_constant.mjs.map +1 -0
  165. package/dist/theme/data-attribute/parse-data-attribute.cjs +24 -0
  166. package/dist/theme/data-attribute/parse-data-attribute.cjs.map +1 -0
  167. package/dist/theme/data-attribute/parse-data-attribute.d.cts +21 -0
  168. package/dist/theme/data-attribute/parse-data-attribute.d.cts.map +1 -0
  169. package/dist/theme/data-attribute/parse-data-attribute.d.mts +21 -0
  170. package/dist/theme/data-attribute/parse-data-attribute.d.mts.map +1 -0
  171. package/dist/theme/data-attribute/parse-data-attribute.mjs +24 -0
  172. package/dist/theme/data-attribute/parse-data-attribute.mjs.map +1 -0
  173. package/dist/theme/data-attribute/read-data-attribute.cjs +23 -0
  174. package/dist/theme/data-attribute/read-data-attribute.cjs.map +1 -0
  175. package/dist/theme/data-attribute/read-data-attribute.d.cts +21 -0
  176. package/dist/theme/data-attribute/read-data-attribute.d.cts.map +1 -0
  177. package/dist/theme/data-attribute/read-data-attribute.d.mts +21 -0
  178. package/dist/theme/data-attribute/read-data-attribute.d.mts.map +1 -0
  179. package/dist/theme/data-attribute/read-data-attribute.mjs +23 -0
  180. package/dist/theme/data-attribute/read-data-attribute.mjs.map +1 -0
  181. package/dist/theme/data-attribute/stringify-data-attribute.cjs +33 -0
  182. package/dist/theme/data-attribute/stringify-data-attribute.cjs.map +1 -0
  183. package/dist/theme/data-attribute/stringify-data-attribute.d.cts +23 -0
  184. package/dist/theme/data-attribute/stringify-data-attribute.d.cts.map +1 -0
  185. package/dist/theme/data-attribute/stringify-data-attribute.d.mts +23 -0
  186. package/dist/theme/data-attribute/stringify-data-attribute.d.mts.map +1 -0
  187. package/dist/theme/data-attribute/stringify-data-attribute.mjs +33 -0
  188. package/dist/theme/data-attribute/stringify-data-attribute.mjs.map +1 -0
  189. package/dist/theme/data-attribute/subscribe-data-attribute.cjs +28 -0
  190. package/dist/theme/data-attribute/subscribe-data-attribute.cjs.map +1 -0
  191. package/dist/theme/data-attribute/subscribe-data-attribute.d.cts +22 -0
  192. package/dist/theme/data-attribute/subscribe-data-attribute.d.cts.map +1 -0
  193. package/dist/theme/data-attribute/subscribe-data-attribute.d.mts +22 -0
  194. package/dist/theme/data-attribute/subscribe-data-attribute.d.mts.map +1 -0
  195. package/dist/theme/data-attribute/subscribe-data-attribute.mjs +28 -0
  196. package/dist/theme/data-attribute/subscribe-data-attribute.mjs.map +1 -0
  197. package/dist/theme/data-attribute/write-data-attribute.cjs +30 -0
  198. package/dist/theme/data-attribute/write-data-attribute.cjs.map +1 -0
  199. package/dist/theme/data-attribute/write-data-attribute.d.cts +21 -0
  200. package/dist/theme/data-attribute/write-data-attribute.d.cts.map +1 -0
  201. package/dist/theme/data-attribute/write-data-attribute.d.mts +21 -0
  202. package/dist/theme/data-attribute/write-data-attribute.d.mts.map +1 -0
  203. package/dist/theme/data-attribute/write-data-attribute.mjs +30 -0
  204. package/dist/theme/data-attribute/write-data-attribute.mjs.map +1 -0
  205. package/dist/theme/local-storage/read-local-storage.cjs +22 -0
  206. package/dist/theme/local-storage/read-local-storage.cjs.map +1 -0
  207. package/dist/theme/local-storage/read-local-storage.d.cts +19 -0
  208. package/dist/theme/local-storage/read-local-storage.d.cts.map +1 -0
  209. package/dist/theme/local-storage/read-local-storage.d.mts +19 -0
  210. package/dist/theme/local-storage/read-local-storage.d.mts.map +1 -0
  211. package/dist/theme/local-storage/read-local-storage.mjs +22 -0
  212. package/dist/theme/local-storage/read-local-storage.mjs.map +1 -0
  213. package/dist/theme/local-storage/write-local-storage.cjs +26 -0
  214. package/dist/theme/local-storage/write-local-storage.cjs.map +1 -0
  215. package/dist/theme/local-storage/write-local-storage.d.cts +23 -0
  216. package/dist/theme/local-storage/write-local-storage.d.cts.map +1 -0
  217. package/dist/theme/local-storage/write-local-storage.d.mts +23 -0
  218. package/dist/theme/local-storage/write-local-storage.d.mts.map +1 -0
  219. package/dist/theme/local-storage/write-local-storage.mjs +26 -0
  220. package/dist/theme/local-storage/write-local-storage.mjs.map +1 -0
  221. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.cjs +20 -0
  222. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.cjs.map +1 -0
  223. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.d.cts +23 -0
  224. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.d.cts.map +1 -0
  225. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.d.mts +23 -0
  226. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.d.mts.map +1 -0
  227. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.mjs +20 -0
  228. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.mjs.map +1 -0
  229. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.cjs +20 -0
  230. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.cjs.map +1 -0
  231. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.d.cts +20 -0
  232. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.d.cts.map +1 -0
  233. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.d.mts +20 -0
  234. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.d.mts.map +1 -0
  235. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.mjs +20 -0
  236. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.mjs.map +1 -0
  237. package/dist/theme/session-storage/read-session-storage.cjs +22 -0
  238. package/dist/theme/session-storage/read-session-storage.cjs.map +1 -0
  239. package/dist/theme/session-storage/read-session-storage.d.cts +19 -0
  240. package/dist/theme/session-storage/read-session-storage.d.cts.map +1 -0
  241. package/dist/theme/session-storage/read-session-storage.d.mts +19 -0
  242. package/dist/theme/session-storage/read-session-storage.d.mts.map +1 -0
  243. package/dist/theme/session-storage/read-session-storage.mjs +22 -0
  244. package/dist/theme/session-storage/read-session-storage.mjs.map +1 -0
  245. package/dist/theme/session-storage/write-session-storage.cjs +26 -0
  246. package/dist/theme/session-storage/write-session-storage.cjs.map +1 -0
  247. package/dist/theme/session-storage/write-session-storage.d.cts +23 -0
  248. package/dist/theme/session-storage/write-session-storage.d.cts.map +1 -0
  249. package/dist/theme/session-storage/write-session-storage.d.mts +23 -0
  250. package/dist/theme/session-storage/write-session-storage.d.mts.map +1 -0
  251. package/dist/theme/session-storage/write-session-storage.mjs +26 -0
  252. package/dist/theme/session-storage/write-session-storage.mjs.map +1 -0
  253. package/dist/theme/theme-entry.types.d.cts +13 -1
  254. package/dist/theme/theme-entry.types.d.cts.map +1 -1
  255. package/dist/theme/theme-entry.types.d.mts +13 -1
  256. package/dist/theme/theme-entry.types.d.mts.map +1 -1
  257. package/dist/theme/theme-map.types.d.cts +11 -3
  258. package/dist/theme/theme-map.types.d.cts.map +1 -1
  259. package/dist/theme/theme-map.types.d.mts +11 -3
  260. package/dist/theme/theme-map.types.d.mts.map +1 -1
  261. package/dist/theme/theme-store/async-theme-store.types.d.cts +1 -1
  262. package/dist/theme/theme-store/async-theme-store.types.d.cts.map +1 -1
  263. package/dist/theme/theme-store/async-theme-store.types.d.mts +1 -1
  264. package/dist/theme/theme-store/async-theme-store.types.d.mts.map +1 -1
  265. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs +22 -19
  266. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs.map +1 -1
  267. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.cts +7 -2
  268. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.cts.map +1 -1
  269. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.mts +7 -2
  270. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.mts.map +1 -1
  271. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs +22 -19
  272. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs.map +1 -1
  273. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.cjs +18 -36
  274. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.cjs.map +1 -1
  275. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.cts +5 -3
  276. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.cts.map +1 -1
  277. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.mts +5 -3
  278. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.mts.map +1 -1
  279. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.mjs +18 -36
  280. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.mjs.map +1 -1
  281. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs +40 -20
  282. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs.map +1 -1
  283. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.cts +30 -7
  284. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.cts.map +1 -1
  285. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.mts +30 -7
  286. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.mts.map +1 -1
  287. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs +40 -20
  288. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs.map +1 -1
  289. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.cjs +1 -1
  290. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.cjs.map +1 -1
  291. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.cts +1 -1
  292. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.mts +1 -1
  293. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.mjs +1 -1
  294. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.mjs.map +1 -1
  295. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.cjs +13 -12
  296. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.cjs.map +1 -1
  297. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.cts +8 -2
  298. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.cts.map +1 -1
  299. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.mts +8 -2
  300. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.mts.map +1 -1
  301. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs +13 -12
  302. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs.map +1 -1
  303. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.cjs +4 -5
  304. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.cjs.map +1 -1
  305. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.cts.map +1 -1
  306. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.mts.map +1 -1
  307. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs +4 -5
  308. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs.map +1 -1
  309. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.cjs +13 -12
  310. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.cjs.map +1 -1
  311. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.cts +8 -2
  312. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.cts.map +1 -1
  313. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.mts +8 -2
  314. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.mts.map +1 -1
  315. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs +13 -12
  316. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs.map +1 -1
  317. package/dist/theme/theme-store/theme-store.types.d.cts +1 -1
  318. package/dist/theme/theme-store/theme-store.types.d.cts.map +1 -1
  319. package/dist/theme/theme-store/theme-store.types.d.mts +1 -1
  320. package/dist/theme/theme-store/theme-store.types.d.mts.map +1 -1
  321. package/dist/theme/web-storage/read-web-storage.cjs +20 -0
  322. package/dist/theme/web-storage/read-web-storage.cjs.map +1 -0
  323. package/dist/theme/web-storage/read-web-storage.d.cts +21 -0
  324. package/dist/theme/web-storage/read-web-storage.d.cts.map +1 -0
  325. package/dist/theme/web-storage/read-web-storage.d.mts +21 -0
  326. package/dist/theme/web-storage/read-web-storage.d.mts.map +1 -0
  327. package/dist/theme/web-storage/read-web-storage.mjs +20 -0
  328. package/dist/theme/web-storage/read-web-storage.mjs.map +1 -0
  329. package/dist/theme/web-storage/write-web-storage.cjs +33 -0
  330. package/dist/theme/web-storage/write-web-storage.cjs.map +1 -0
  331. package/dist/theme/web-storage/write-web-storage.d.cts +25 -0
  332. package/dist/theme/web-storage/write-web-storage.d.cts.map +1 -0
  333. package/dist/theme/web-storage/write-web-storage.d.mts +25 -0
  334. package/dist/theme/web-storage/write-web-storage.d.mts.map +1 -0
  335. package/dist/theme/web-storage/write-web-storage.mjs +32 -0
  336. package/dist/theme/web-storage/write-web-storage.mjs.map +1 -0
  337. package/dist/theme.cjs +41 -1
  338. package/dist/theme.d.cts +23 -3
  339. package/dist/theme.d.mts +23 -3
  340. package/dist/theme.mjs +21 -1
  341. package/dist/utils/append-id.cjs +2 -2
  342. package/dist/utils/append-id.cjs.map +1 -1
  343. package/dist/utils/append-id.d.cts +3 -3
  344. package/dist/utils/append-id.d.mts +3 -3
  345. package/dist/utils/append-id.mjs +2 -2
  346. package/dist/utils/append-id.mjs.map +1 -1
  347. package/package.json +1 -1
  348. package/src/attributes/get-attribute.ts +5 -2
  349. package/src/attributes/get-data-attribute.ts +5 -2
  350. package/src/attributes/observe-attribute.ts +2 -2
  351. package/src/attributes/observe-data-attribute.ts +2 -2
  352. package/src/color-scheme/color-scheme.types.ts +7 -0
  353. package/src/color-scheme/get-prefers-color-scheme.ts +6 -4
  354. package/src/color-scheme/observe-prefers-color-scheme.ts +3 -1
  355. package/src/index.ts +1 -0
  356. package/src/react/hooks/use-attribute.ts +11 -11
  357. package/src/react/hooks/use-theme-by-class-name.ts +5 -10
  358. package/src/react/hooks/use-theme-by-data-attribute.ts +5 -12
  359. package/src/react/hooks/use-theme-by-local-storage.ts +3 -9
  360. package/src/react/theme/create-theme-hook.ts +4 -6
  361. package/src/testing/theme/theme-result-card.tsx +1 -0
  362. package/src/theme/_utils/match-attribute-value-to-theme.ts +36 -0
  363. package/src/theme/_utils/parse-stored-theme.ts +51 -11
  364. package/src/theme/_utils/resolve-theme-map-value.ts +15 -0
  365. package/src/theme/_utils/set-theme-to-stores.ts +3 -3
  366. package/src/theme/class-name/parse-class-name.ts +31 -0
  367. package/src/theme/class-name/read-class-name.ts +24 -0
  368. package/src/theme/class-name/stringify-class-name.ts +36 -0
  369. package/src/theme/class-name/subscribe-class-name.ts +39 -0
  370. package/src/theme/class-name/write-class-name.ts +24 -0
  371. package/src/theme/compose-theme-stores.ts +1 -1
  372. package/src/theme/cookie/_cookie-utils.ts +45 -0
  373. package/src/theme/cookie/read-cookie-theme.ts +33 -0
  374. package/src/theme/cookie/write-cookie-theme.ts +48 -0
  375. package/src/theme/data-attribute/_constant.ts +1 -0
  376. package/src/theme/data-attribute/parse-data-attribute.ts +25 -0
  377. package/src/theme/data-attribute/read-data-attribute.ts +29 -0
  378. package/src/theme/data-attribute/stringify-data-attribute.ts +39 -0
  379. package/src/theme/data-attribute/subscribe-data-attribute.ts +39 -0
  380. package/src/theme/data-attribute/write-data-attribute.ts +40 -0
  381. package/src/theme/local-storage/read-local-storage.ts +23 -0
  382. package/src/theme/local-storage/write-local-storage.ts +31 -0
  383. package/src/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.ts +30 -0
  384. package/src/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.ts +24 -0
  385. package/src/theme/session-storage/read-session-storage.ts +23 -0
  386. package/src/theme/session-storage/write-session-storage.ts +31 -0
  387. package/src/theme/theme-entry.types.ts +21 -0
  388. package/src/theme/theme-map.types.ts +9 -2
  389. package/src/theme/theme-store/async-theme-store.types.ts +1 -3
  390. package/src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts +20 -26
  391. package/src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts +18 -63
  392. package/src/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.ts +42 -29
  393. package/src/theme/theme-store/in-memory-theme-store/in-memory-theme-store.ts +1 -1
  394. package/src/theme/theme-store/local-storage-theme-store/local-storage-theme-store.ts +17 -20
  395. package/src/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.ts +4 -5
  396. package/src/theme/theme-store/session-storage-theme-store/session-storage-theme-store.ts +17 -20
  397. package/src/theme/theme-store/theme-store.types.ts +1 -3
  398. package/src/theme/web-storage/read-web-storage.ts +22 -0
  399. package/src/theme/web-storage/write-web-storage.ts +46 -0
  400. package/src/theme.ts +20 -0
  401. package/src/utils/append-id.ts +3 -3
  402. package/dist/theme/class-name/apply-theme-to-class-name.cjs +0 -23
  403. package/dist/theme/class-name/apply-theme-to-class-name.cjs.map +0 -1
  404. package/dist/theme/class-name/apply-theme-to-class-name.mjs +0 -22
  405. package/dist/theme/class-name/apply-theme-to-class-name.mjs.map +0 -1
  406. package/dist/theme/class-name/resolve-theme-from-class-name.cjs +0 -23
  407. package/dist/theme/class-name/resolve-theme-from-class-name.cjs.map +0 -1
  408. package/dist/theme/class-name/resolve-theme-from-class-name.mjs +0 -22
  409. package/dist/theme/class-name/resolve-theme-from-class-name.mjs.map +0 -1
  410. package/dist/theme/data-attribute/apply-theme-to-data-attribute.cjs +0 -23
  411. package/dist/theme/data-attribute/apply-theme-to-data-attribute.cjs.map +0 -1
  412. package/dist/theme/data-attribute/apply-theme-to-data-attribute.mjs +0 -22
  413. package/dist/theme/data-attribute/apply-theme-to-data-attribute.mjs.map +0 -1
  414. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.cjs +0 -23
  415. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.cjs.map +0 -1
  416. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.mjs +0 -22
  417. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.mjs.map +0 -1
  418. package/src/theme/class-name/apply-theme-to-class-name.ts +0 -26
  419. package/src/theme/class-name/resolve-theme-from-class-name.ts +0 -22
  420. package/src/theme/data-attribute/apply-theme-to-data-attribute.ts +0 -27
  421. package/src/theme/data-attribute/resolve-theme-from-data-attribute.ts +0 -23
@@ -1,4 +1,5 @@
1
1
  import { ThemeMap } from "../../theme-map.types.cjs";
2
+ import { ParseStoredTheme, StringifyStoredTheme } from "../../theme-entry.types.cjs";
2
3
  import { ThemeStore } from "../theme-store.types.cjs";
3
4
  import { Required } from "type-plus";
4
5
 
@@ -8,7 +9,9 @@ import { Required } from "type-plus";
8
9
  * Creates a theme store that reads and writes via element class names.
9
10
  *
10
11
  * @param themes - Record mapping theme keys to class name(s)
11
- * @param options.element - Element to operate on (defaults to document.documentElement)
12
+ * @param options.element - Element to operate on (accepts null e.g. from refs). Defaults to document.documentElement.
13
+ * @param options.parse - Custom parser (default: parseClassName)
14
+ * @param options.stringify - Custom serializer (default: stringifyClassName)
12
15
  * @returns ThemeStore
13
16
  *
14
17
  * @example
@@ -21,7 +24,9 @@ import { Required } from "type-plus";
21
24
  * ```
22
25
  */
23
26
  declare function classNameThemeStore<Themes extends ThemeMap>(themes: Themes, options?: {
24
- element?: Element | undefined;
27
+ element?: Element | null | undefined;
28
+ parse?: ParseStoredTheme<Themes> | undefined;
29
+ stringify?: StringifyStoredTheme<Themes> | undefined;
25
30
  }): Required<ThemeStore<Themes>>;
26
31
  //#endregion
27
32
  export { classNameThemeStore };
@@ -1 +1 @@
1
- {"version":3,"file":"class-name-theme-store.d.cts","names":[],"sources":["../../../../src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAyBA;;;;;;;;;;;;;;iBAAgB,mCAAmC,kBAC1C;YACc;IACpB,SAAS,WAAW"}
1
+ {"version":3,"file":"class-name-theme-store.d.cts","names":[],"sources":["../../../../src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AA6BA;;;;;;;;;;;;;;;;iBAAgB,mCAAmC,kBAC1C;YAEG;UACF,iBAAiB;cACb,qBAAqB;IAEhC,SAAS,WAAW"}
@@ -1,4 +1,5 @@
1
1
  import { ThemeMap } from "../../theme-map.types.mjs";
2
+ import { ParseStoredTheme, StringifyStoredTheme } from "../../theme-entry.types.mjs";
2
3
  import { ThemeStore } from "../theme-store.types.mjs";
3
4
  import { Required } from "type-plus";
4
5
 
@@ -8,7 +9,9 @@ import { Required } from "type-plus";
8
9
  * Creates a theme store that reads and writes via element class names.
9
10
  *
10
11
  * @param themes - Record mapping theme keys to class name(s)
11
- * @param options.element - Element to operate on (defaults to document.documentElement)
12
+ * @param options.element - Element to operate on (accepts null e.g. from refs). Defaults to document.documentElement.
13
+ * @param options.parse - Custom parser (default: parseClassName)
14
+ * @param options.stringify - Custom serializer (default: stringifyClassName)
12
15
  * @returns ThemeStore
13
16
  *
14
17
  * @example
@@ -21,7 +24,9 @@ import { Required } from "type-plus";
21
24
  * ```
22
25
  */
23
26
  declare function classNameThemeStore<Themes extends ThemeMap>(themes: Themes, options?: {
24
- element?: Element | undefined;
27
+ element?: Element | null | undefined;
28
+ parse?: ParseStoredTheme<Themes> | undefined;
29
+ stringify?: StringifyStoredTheme<Themes> | undefined;
25
30
  }): Required<ThemeStore<Themes>>;
26
31
  //#endregion
27
32
  export { classNameThemeStore };
@@ -1 +1 @@
1
- {"version":3,"file":"class-name-theme-store.d.mts","names":[],"sources":["../../../../src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAyBA;;;;;;;;;;;;;;iBAAgB,mCAAmC,kBAC1C;YACc;IACpB,SAAS,WAAW"}
1
+ {"version":3,"file":"class-name-theme-store.d.mts","names":[],"sources":["../../../../src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AA6BA;;;;;;;;;;;;;;;;iBAAgB,mCAAmC,kBAC1C;YAEG;UACF,iBAAiB;cACb,qBAAqB;IAEhC,SAAS,WAAW"}
@@ -1,15 +1,18 @@
1
- import { observeAttributes } from "../../../attributes/observe-attribute.mjs";
2
- import { resolveThemeFromClassName } from "../../class-name/resolve-theme-from-class-name.mjs";
3
- import { themeEntry } from "../../theme-entry.mjs";
4
1
  import { dummyThemeStore } from "../../../testing/theme/dummy-theme-store.mjs";
5
- import { applyThemeToClassName } from "../../class-name/apply-theme-to-class-name.mjs";
2
+ import { parseClassName } from "../../class-name/parse-class-name.mjs";
3
+ import { readClassName } from "../../class-name/read-class-name.mjs";
4
+ import { stringifyClassName } from "../../class-name/stringify-class-name.mjs";
5
+ import { subscribeClassName } from "../../class-name/subscribe-class-name.mjs";
6
+ import { writeClassName } from "../../class-name/write-class-name.mjs";
6
7
 
7
8
  //#region src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts
8
9
  /**
9
10
  * Creates a theme store that reads and writes via element class names.
10
11
  *
11
12
  * @param themes - Record mapping theme keys to class name(s)
12
- * @param options.element - Element to operate on (defaults to document.documentElement)
13
+ * @param options.element - Element to operate on (accepts null e.g. from refs). Defaults to document.documentElement.
14
+ * @param options.parse - Custom parser (default: parseClassName)
15
+ * @param options.stringify - Custom serializer (default: stringifyClassName)
13
16
  * @returns ThemeStore
14
17
  *
15
18
  * @example
@@ -24,26 +27,26 @@ import { applyThemeToClassName } from "../../class-name/apply-theme-to-class-nam
24
27
  function classNameThemeStore(themes, options) {
25
28
  const element = options?.element ?? document?.documentElement;
26
29
  if (!element) return dummyThemeStore;
30
+ const parse = options?.parse ?? parseClassName;
31
+ const stringify = options?.stringify ?? stringifyClassName;
27
32
  return {
28
33
  read() {
29
- const theme = resolveThemeFromClassName(themes, element.className);
30
- if (theme === void 0) return void 0;
31
- return themeEntry(themes, theme);
34
+ return readClassName(themes, {
35
+ element,
36
+ parse
37
+ });
32
38
  },
33
39
  write(entry) {
34
- applyThemeToClassName(themes, element, entry);
40
+ writeClassName(themes, entry, {
41
+ element,
42
+ stringify
43
+ });
35
44
  },
36
45
  subscribe(handler) {
37
- let lastEmitted = null;
38
- const observer = observeAttributes({ class: (value) => {
39
- const theme = value ? resolveThemeFromClassName(themes, value) : void 0;
40
- const entry = theme ? themeEntry(themes, theme) : void 0;
41
- const key = theme ?? void 0;
42
- if (lastEmitted === key) return;
43
- lastEmitted = key;
44
- handler(entry);
45
- } }, element);
46
- return () => observer.disconnect();
46
+ return subscribeClassName(themes, handler, {
47
+ element,
48
+ parse
49
+ });
47
50
  }
48
51
  };
49
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"class-name-theme-store.mjs","names":["lastEmitted: keyof Themes | undefined | null"],"sources":["../../../../src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts"],"sourcesContent":["import type { Required } from 'type-plus'\nimport { observeAttributes } from '../../../attributes/observe-attribute.ts'\nimport { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'\nimport { applyThemeToClassName } from '../../class-name/apply-theme-to-class-name.ts'\nimport { resolveThemeFromClassName } from '../../class-name/resolve-theme-from-class-name.ts'\nimport { themeEntry } from '../../theme-entry.ts'\nimport type { ThemeMap } from '../../theme-map.types.ts'\nimport type { ThemeStore } from '../theme-store.types.ts'\n\n/**\n * Creates a theme store that reads and writes via element class names.\n *\n * @param themes - Record mapping theme keys to class name(s)\n * @param options.element - Element to operate on (defaults to document.documentElement)\n * @returns ThemeStore\n *\n * @example\n * ```ts\n * const themes = { current: 'theme-current', grayscale: 'theme-grayscale' }\n * const store = classNameThemeStore(themes)\n * store.read() // returns themeResult from element.className\n * store.write(themeEntry(themes, 'grayscale'))\n * store.subscribe((themeResult) => {})\n * ```\n */\nexport function classNameThemeStore<Themes extends ThemeMap>(\n\tthemes: Themes,\n\toptions?: { element?: Element | undefined }\n): Required<ThemeStore<Themes>> {\n\tconst element = options?.element ?? document?.documentElement\n\n\tif (!element) return dummyThemeStore\n\n\treturn {\n\t\tread() {\n\t\t\tconst theme = resolveThemeFromClassName(themes, element.className)\n\t\t\tif (theme === undefined) return undefined\n\t\t\treturn themeEntry(themes, theme)\n\t\t},\n\t\twrite(entry) {\n\t\t\tapplyThemeToClassName(themes, element, entry)\n\t\t},\n\t\tsubscribe(handler) {\n\t\t\tlet lastEmitted: keyof Themes | undefined | null = null\n\t\t\tconst observer = observeAttributes(\n\t\t\t\t{\n\t\t\t\t\tclass: (value) => {\n\t\t\t\t\t\tconst theme = value ? resolveThemeFromClassName(themes, value) : undefined\n\t\t\t\t\t\tconst entry = theme ? themeEntry(themes, theme) : undefined\n\t\t\t\t\t\tconst key = theme ?? undefined\n\n\t\t\t\t\t\tif (lastEmitted === key) return\n\t\t\t\t\t\tlastEmitted = key\n\t\t\t\t\t\thandler(entry)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\telement\n\t\t\t)\n\t\t\treturn () => observer.disconnect()\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,oBACf,QACA,SAC+B;CAC/B,MAAM,UAAU,SAAS,WAAW,UAAU;AAE9C,KAAI,CAAC,QAAS,QAAO;AAErB,QAAO;EACN,OAAO;GACN,MAAM,QAAQ,0BAA0B,QAAQ,QAAQ,UAAU;AAClE,OAAI,UAAU,OAAW,QAAO;AAChC,UAAO,WAAW,QAAQ,MAAM;;EAEjC,MAAM,OAAO;AACZ,yBAAsB,QAAQ,SAAS,MAAM;;EAE9C,UAAU,SAAS;GAClB,IAAIA,cAA+C;GACnD,MAAM,WAAW,kBAChB,EACC,QAAQ,UAAU;IACjB,MAAM,QAAQ,QAAQ,0BAA0B,QAAQ,MAAM,GAAG;IACjE,MAAM,QAAQ,QAAQ,WAAW,QAAQ,MAAM,GAAG;IAClD,MAAM,MAAM,SAAS;AAErB,QAAI,gBAAgB,IAAK;AACzB,kBAAc;AACd,YAAQ,MAAM;MAEf,EACD,QACA;AACD,gBAAa,SAAS,YAAY;;EAEnC"}
1
+ {"version":3,"file":"class-name-theme-store.mjs","names":[],"sources":["../../../../src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts"],"sourcesContent":["import type { Required } from 'type-plus'\nimport { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'\nimport { parseClassName } from '../../class-name/parse-class-name.ts'\nimport { readClassName } from '../../class-name/read-class-name.ts'\nimport { stringifyClassName } from '../../class-name/stringify-class-name.ts'\nimport { subscribeClassName } from '../../class-name/subscribe-class-name.ts'\nimport { writeClassName } from '../../class-name/write-class-name.ts'\nimport type { ParseStoredTheme, StringifyStoredTheme } from '../../theme-entry.types.ts'\nimport type { ThemeMap } from '../../theme-map.types.ts'\nimport type { ThemeStore } from '../theme-store.types.ts'\n\n/**\n * Creates a theme store that reads and writes via element class names.\n *\n * @param themes - Record mapping theme keys to class name(s)\n * @param options.element - Element to operate on (accepts null e.g. from refs). Defaults to document.documentElement.\n * @param options.parse - Custom parser (default: parseClassName)\n * @param options.stringify - Custom serializer (default: stringifyClassName)\n * @returns ThemeStore\n *\n * @example\n * ```ts\n * const themes = { current: 'theme-current', grayscale: 'theme-grayscale' }\n * const store = classNameThemeStore(themes)\n * store.read() // returns themeResult from element.className\n * store.write(themeEntry(themes, 'grayscale'))\n * store.subscribe((themeResult) => {})\n * ```\n */\nexport function classNameThemeStore<Themes extends ThemeMap>(\n\tthemes: Themes,\n\toptions?: {\n\t\telement?: Element | null | undefined\n\t\tparse?: ParseStoredTheme<Themes> | undefined\n\t\tstringify?: StringifyStoredTheme<Themes> | undefined\n\t}\n): Required<ThemeStore<Themes>> {\n\tconst element = options?.element ?? document?.documentElement\n\n\tif (!element) return dummyThemeStore\n\n\tconst parse = options?.parse ?? parseClassName\n\tconst stringify = options?.stringify ?? stringifyClassName\n\n\treturn {\n\t\tread() {\n\t\t\treturn readClassName(themes, { element, parse })\n\t\t},\n\t\twrite(entry) {\n\t\t\twriteClassName(themes, entry, { element, stringify })\n\t\t},\n\t\tsubscribe(handler) {\n\t\t\treturn subscribeClassName(themes, handler, { element, parse })\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,oBACf,QACA,SAK+B;CAC/B,MAAM,UAAU,SAAS,WAAW,UAAU;AAE9C,KAAI,CAAC,QAAS,QAAO;CAErB,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,YAAY,SAAS,aAAa;AAExC,QAAO;EACN,OAAO;AACN,UAAO,cAAc,QAAQ;IAAE;IAAS;IAAO,CAAC;;EAEjD,MAAM,OAAO;AACZ,kBAAe,QAAQ,OAAO;IAAE;IAAS;IAAW,CAAC;;EAEtD,UAAU,SAAS;AAClB,UAAO,mBAAmB,QAAQ,SAAS;IAAE;IAAS;IAAO,CAAC;;EAE/D"}
@@ -1,24 +1,10 @@
1
- const require_theme_entry = require('../../theme-entry.cjs');
2
1
  const require_dummy_theme_store = require('../../../testing/theme/dummy-theme-store.cjs');
3
2
  const require_parse_stored_theme = require('../../_utils/parse-stored-theme.cjs');
3
+ const require__cookie_utils = require('../../cookie/_cookie-utils.cjs');
4
+ const require_read_cookie_theme = require('../../cookie/read-cookie-theme.cjs');
5
+ const require_write_cookie_theme = require('../../cookie/write-cookie-theme.cjs');
4
6
 
5
7
  //#region src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts
6
- function getCookieValue(name) {
7
- if (typeof document === "undefined" || !document.cookie) return null;
8
- const value = document.cookie.match(/* @__PURE__ */ new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))?.[1];
9
- return value !== void 0 ? decodeURIComponent(value) : null;
10
- }
11
- function setCookie(name, value, options) {
12
- const parts = [`${name}=${encodeURIComponent(value)}`];
13
- parts.push(`path=${options.path ?? "/"}`);
14
- if (options.maxAge !== void 0) parts.push(`max-age=${options.maxAge}`);
15
- if (options.sameSite !== void 0) parts.push(`samesite=${options.sameSite}`);
16
- if (options.secure) parts.push("secure");
17
- document.cookie = parts.join("; ");
18
- }
19
- function deleteCookie(name, path = "/") {
20
- document.cookie = `${name}=; path=${path}; max-age=0`;
21
- }
22
8
  /**
23
9
  * Creates a theme store backed by cookies.
24
10
  *
@@ -32,6 +18,7 @@ function deleteCookie(name, path = "/") {
32
18
  * @param options.maxAge - Cookie max-age in seconds
33
19
  * @param options.sameSite - Cookie sameSite attribute
34
20
  * @param options.secure - Cookie secure attribute
21
+ * @param options.parse - Optional custom parser for stored string (default: parseStoredTheme)
35
22
  * @returns ThemeStore
36
23
  *
37
24
  * @example
@@ -44,14 +31,16 @@ function deleteCookie(name, path = "/") {
44
31
  * ```
45
32
  */
46
33
  function cookieThemeStore(themes, options) {
47
- const { cookieName, path = "/", maxAge, sameSite, secure } = options;
34
+ const { cookieName, path = "/", maxAge, sameSite, secure, parse = require_parse_stored_theme.parseStoredTheme } = options;
48
35
  if (document.cookie === void 0) return require_dummy_theme_store.dummyThemeStore;
49
36
  const handlers = /* @__PURE__ */ new Set();
50
37
  let lastNotifiedKey = read()?.theme ?? void 0;
51
38
  function read() {
52
- const theme = require_parse_stored_theme.parseStoredTheme(themes, getCookieValue(cookieName));
53
- if (theme === void 0) return void 0;
54
- return require_theme_entry.themeEntry(themes, theme);
39
+ return require_read_cookie_theme.readCookieTheme(themes, {
40
+ cookieName,
41
+ path,
42
+ parse
43
+ });
55
44
  }
56
45
  function notify() {
57
46
  const result = read();
@@ -64,14 +53,13 @@ function cookieThemeStore(themes, options) {
64
53
  read,
65
54
  write(entry) {
66
55
  try {
67
- if (entry === void 0) deleteCookie(cookieName, path);
68
- else {
69
- const opts = { path };
70
- if (maxAge !== void 0) opts.maxAge = maxAge;
71
- if (sameSite !== void 0) opts.sameSite = sameSite;
72
- if (secure) opts.secure = true;
73
- setCookie(cookieName, JSON.stringify(entry), opts);
74
- }
56
+ require_write_cookie_theme.writeCookieTheme(themes, entry, {
57
+ cookieName,
58
+ path,
59
+ maxAge,
60
+ sameSite,
61
+ secure
62
+ });
75
63
  notify();
76
64
  } catch {}
77
65
  },
@@ -83,10 +71,6 @@ function cookieThemeStore(themes, options) {
83
71
  }
84
72
  };
85
73
  }
86
- function getCookieFromHeader(cookieHeader, name) {
87
- const value = cookieHeader.match(/* @__PURE__ */ new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))?.[1];
88
- return value !== void 0 ? decodeURIComponent(value.trim()) : null;
89
- }
90
74
  /**
91
75
  * Reads the theme from cookies during SSR. Use with the request's Cookie header or
92
76
  * a framework's cookie API (e.g. Next.js cookies()).
@@ -110,9 +94,7 @@ function getCookieFromHeader(cookieHeader, name) {
110
94
  */
111
95
  function getThemeFromCookie(cookieSource, themes, options = {}) {
112
96
  const cookieName = options.cookieName ?? "theme";
113
- const theme = require_parse_stored_theme.parseStoredTheme(themes, typeof cookieSource === "function" ? cookieSource(cookieName) ?? null : cookieSource ? getCookieFromHeader(cookieSource, cookieName) : null);
114
- if (theme === void 0) return void 0;
115
- return require_theme_entry.themeEntry(themes, theme);
97
+ return require_parse_stored_theme.parseStoredTheme(themes, (typeof cookieSource === "function" ? cookieSource(cookieName) ?? null : cookieSource ? require__cookie_utils.getCookieFromHeader(cookieSource, cookieName) : null) ?? void 0);
116
98
  }
117
99
 
118
100
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"cookie-theme-store.cjs","names":["dummyThemeStore","lastNotifiedKey: keyof Themes | undefined","parseStoredTheme","themeEntry","opts: {\n\t\t\t\t\t\tpath: string\n\t\t\t\t\t\tmaxAge?: number\n\t\t\t\t\t\tsameSite?: 'lax' | 'strict' | 'none'\n\t\t\t\t\t\tsecure?: boolean\n\t\t\t\t\t}"],"sources":["../../../../src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts"],"sourcesContent":["import type { Required } from 'type-plus'\nimport { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'\nimport { parseStoredTheme } from '../../_utils/parse-stored-theme.ts'\nimport { themeEntry } from '../../theme-entry.ts'\nimport type { ThemeEntry } from '../../theme-entry.types.ts'\nimport type { ThemeMap } from '../../theme-map.types.ts'\nimport type { ThemeStore } from '../theme-store.types.ts'\n\nexport interface CookieThemeStoreOptions {\n\tcookieName: string\n\tpath?: string | undefined\n\tmaxAge?: number | undefined\n\tsameSite?: 'lax' | 'strict' | 'none' | undefined\n\tsecure?: boolean | undefined\n}\n\nfunction getCookieValue(name: string): string | null {\n\tif (typeof document === 'undefined' || !document.cookie) return null\n\tconst match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`))\n\tconst value = match?.[1]\n\treturn value !== undefined ? decodeURIComponent(value) : null\n}\n\nfunction setCookie(\n\tname: string,\n\tvalue: string,\n\toptions: {\n\t\tpath?: string | undefined\n\t\tmaxAge?: number | undefined\n\t\tsameSite?: 'lax' | 'strict' | 'none' | undefined\n\t\tsecure?: boolean | undefined\n\t}\n) {\n\tconst parts = [`${name}=${encodeURIComponent(value)}`]\n\tparts.push(`path=${options.path ?? '/'}`)\n\tif (options.maxAge !== undefined) parts.push(`max-age=${options.maxAge}`)\n\tif (options.sameSite !== undefined) parts.push(`samesite=${options.sameSite}`)\n\tif (options.secure) parts.push('secure')\n\t// biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API has limited support; document.cookie is standard for theme persistence\n\tdocument.cookie = parts.join('; ')\n}\n\nfunction deleteCookie(name: string, path = '/') {\n\t// biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API has limited support; document.cookie is standard for theme persistence\n\tdocument.cookie = `${name}=; path=${path}; max-age=0`\n}\n\n/**\n * Creates a theme store backed by cookies.\n *\n * Persists across sessions. Cookies are sent with every request, so the server can\n * read the theme during SSR to avoid flash of wrong theme. Cross-tab sync is not\n * supported (cookies have no StorageEvent).\n *\n * @param themes - Record mapping theme keys to values (for validation)\n * @param options.cookieName - Cookie name for theme storage\n * @param options.path - Cookie path (default: '/')\n * @param options.maxAge - Cookie max-age in seconds\n * @param options.sameSite - Cookie sameSite attribute\n * @param options.secure - Cookie secure attribute\n * @returns ThemeStore\n *\n * @example\n * ```ts\n * const themes = { current: 'theme-current', grayscale: 'theme-grayscale' }\n * const store = cookieThemeStore(themes, { cookieName: 'theme' })\n * store.read()\n * store.write(themeEntry(themes, 'grayscale'))\n * store.subscribe((themeResult) => {})\n * ```\n */\nexport function cookieThemeStore<Themes extends ThemeMap>(\n\tthemes: Themes,\n\toptions: CookieThemeStoreOptions\n): Required<ThemeStore<Themes>> {\n\tconst { cookieName, path = '/', maxAge, sameSite, secure } = options\n\n\tif (document.cookie === undefined) {\n\t\treturn dummyThemeStore\n\t}\n\n\tconst handlers = new Set<(theme: ThemeEntry<Themes> | undefined) => void>()\n\tlet lastNotifiedKey: keyof Themes | undefined = read()?.theme ?? undefined\n\n\tfunction read() {\n\t\tconst stored = getCookieValue(cookieName)\n\t\tconst theme = parseStoredTheme(themes, stored)\n\t\tif (theme === undefined) return undefined\n\t\treturn themeEntry(themes, theme)\n\t}\n\n\tfunction notify() {\n\t\tconst result = read()\n\t\tconst key = result?.theme ?? undefined\n\t\tif (key === lastNotifiedKey) return\n\t\tlastNotifiedKey = key\n\t\tfor (const h of handlers) h(result)\n\t}\n\n\treturn {\n\t\tread,\n\t\twrite(entry) {\n\t\t\ttry {\n\t\t\t\tif (entry === undefined) {\n\t\t\t\t\tdeleteCookie(cookieName, path)\n\t\t\t\t} else {\n\t\t\t\t\tconst opts: {\n\t\t\t\t\t\tpath: string\n\t\t\t\t\t\tmaxAge?: number\n\t\t\t\t\t\tsameSite?: 'lax' | 'strict' | 'none'\n\t\t\t\t\t\tsecure?: boolean\n\t\t\t\t\t} = { path }\n\t\t\t\t\tif (maxAge !== undefined) opts.maxAge = maxAge\n\t\t\t\t\tif (sameSite !== undefined) opts.sameSite = sameSite\n\t\t\t\t\tif (secure) opts.secure = true\n\t\t\t\t\tsetCookie(cookieName, JSON.stringify(entry), opts)\n\t\t\t\t}\n\t\t\t\tnotify()\n\t\t\t} catch {\n\t\t\t\t// Ignore quota or other errors\n\t\t\t}\n\t\t},\n\t\tsubscribe(handler) {\n\t\t\thandlers.add(handler)\n\t\t\treturn () => {\n\t\t\t\thandlers.delete(handler)\n\t\t\t}\n\t\t}\n\t} satisfies ThemeStore<Themes>\n}\n\nfunction getCookieFromHeader(cookieHeader: string, name: string): string | null {\n\tconst match = cookieHeader.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`))\n\tconst value = match?.[1]\n\treturn value !== undefined ? decodeURIComponent(value.trim()) : null\n}\n\n/**\n * Reads the theme from cookies during SSR. Use with the request's Cookie header or\n * a framework's cookie API (e.g. Next.js cookies()).\n *\n * @param cookieSource - Raw Cookie header string, or a getter (name) => value for framework APIs\n * @param themes - Record mapping theme keys to values (for validation)\n * @param options - Optional cookie name (default: 'theme')\n * @returns ThemeEntry if valid cookie found, otherwise undefined\n *\n * @example\n * ```ts\n * // With raw Cookie header (Express, Remix, etc.)\n * const theme = getThemeFromCookie(request.headers.get('Cookie') ?? '', themes)\n *\n * // With Next.js cookies()\n * const theme = getThemeFromCookie(\n * (name) => cookies().get(name)?.value ?? undefined,\n * themes\n * )\n * ```\n */\nexport function getThemeFromCookie<Themes extends ThemeMap>(\n\tcookieSource: string | null | undefined | ((name: string) => string | null | undefined),\n\tthemes: Themes,\n\toptions: { cookieName?: string | undefined } = {}\n): ThemeEntry<Themes> | undefined {\n\tconst cookieName = options.cookieName ?? 'theme'\n\tconst stored =\n\t\ttypeof cookieSource === 'function'\n\t\t\t? (cookieSource(cookieName) ?? null)\n\t\t\t: cookieSource\n\t\t\t\t? getCookieFromHeader(cookieSource, cookieName)\n\t\t\t\t: null\n\tconst theme = parseStoredTheme(themes, stored)\n\tif (theme === undefined) return undefined\n\treturn themeEntry(themes, theme)\n}\n"],"mappings":";;;;;AAgBA,SAAS,eAAe,MAA6B;AACpD,KAAI,OAAO,aAAa,eAAe,CAAC,SAAS,OAAQ,QAAO;CAEhE,MAAM,QADQ,SAAS,OAAO,sBAAM,IAAI,OAAO,cAAc,KAAK,UAAU,CAAC,GACvD;AACtB,QAAO,UAAU,SAAY,mBAAmB,MAAM,GAAG;;AAG1D,SAAS,UACR,MACA,OACA,SAMC;CACD,MAAM,QAAQ,CAAC,GAAG,KAAK,GAAG,mBAAmB,MAAM,GAAG;AACtD,OAAM,KAAK,QAAQ,QAAQ,QAAQ,MAAM;AACzC,KAAI,QAAQ,WAAW,OAAW,OAAM,KAAK,WAAW,QAAQ,SAAS;AACzE,KAAI,QAAQ,aAAa,OAAW,OAAM,KAAK,YAAY,QAAQ,WAAW;AAC9E,KAAI,QAAQ,OAAQ,OAAM,KAAK,SAAS;AAExC,UAAS,SAAS,MAAM,KAAK,KAAK;;AAGnC,SAAS,aAAa,MAAc,OAAO,KAAK;AAE/C,UAAS,SAAS,GAAG,KAAK,UAAU,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;AA2B1C,SAAgB,iBACf,QACA,SAC+B;CAC/B,MAAM,EAAE,YAAY,OAAO,KAAK,QAAQ,UAAU,WAAW;AAE7D,KAAI,SAAS,WAAW,OACvB,QAAOA;CAGR,MAAM,2BAAW,IAAI,KAAsD;CAC3E,IAAIC,kBAA4C,MAAM,EAAE,SAAS;CAEjE,SAAS,OAAO;EAEf,MAAM,QAAQC,4CAAiB,QADhB,eAAe,WAAW,CACK;AAC9C,MAAI,UAAU,OAAW,QAAO;AAChC,SAAOC,+BAAW,QAAQ,MAAM;;CAGjC,SAAS,SAAS;EACjB,MAAM,SAAS,MAAM;EACrB,MAAM,MAAM,QAAQ,SAAS;AAC7B,MAAI,QAAQ,gBAAiB;AAC7B,oBAAkB;AAClB,OAAK,MAAM,KAAK,SAAU,GAAE,OAAO;;AAGpC,QAAO;EACN;EACA,MAAM,OAAO;AACZ,OAAI;AACH,QAAI,UAAU,OACb,cAAa,YAAY,KAAK;SACxB;KACN,MAAMC,OAKF,EAAE,MAAM;AACZ,SAAI,WAAW,OAAW,MAAK,SAAS;AACxC,SAAI,aAAa,OAAW,MAAK,WAAW;AAC5C,SAAI,OAAQ,MAAK,SAAS;AAC1B,eAAU,YAAY,KAAK,UAAU,MAAM,EAAE,KAAK;;AAEnD,YAAQ;WACD;;EAIT,UAAU,SAAS;AAClB,YAAS,IAAI,QAAQ;AACrB,gBAAa;AACZ,aAAS,OAAO,QAAQ;;;EAG1B;;AAGF,SAAS,oBAAoB,cAAsB,MAA6B;CAE/E,MAAM,QADQ,aAAa,sBAAM,IAAI,OAAO,cAAc,KAAK,UAAU,CAAC,GACpD;AACtB,QAAO,UAAU,SAAY,mBAAmB,MAAM,MAAM,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;AAwBjE,SAAgB,mBACf,cACA,QACA,UAA+C,EAAE,EAChB;CACjC,MAAM,aAAa,QAAQ,cAAc;CAOzC,MAAM,QAAQF,4CAAiB,QAL9B,OAAO,iBAAiB,aACpB,aAAa,WAAW,IAAI,OAC7B,eACC,oBAAoB,cAAc,WAAW,GAC7C,KACyC;AAC9C,KAAI,UAAU,OAAW,QAAO;AAChC,QAAOC,+BAAW,QAAQ,MAAM"}
1
+ {"version":3,"file":"cookie-theme-store.cjs","names":["parseStoredTheme","dummyThemeStore","lastNotifiedKey: keyof Themes | undefined","readCookieTheme","getCookieFromHeader"],"sources":["../../../../src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts"],"sourcesContent":["import type { Required } from 'type-plus'\nimport { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'\nimport { parseStoredTheme } from '../../_utils/parse-stored-theme.ts'\nimport { getCookieFromHeader } from '../../cookie/_cookie-utils.ts'\nimport { readCookieTheme } from '../../cookie/read-cookie-theme.ts'\nimport { writeCookieTheme } from '../../cookie/write-cookie-theme.ts'\nimport type { ParseStoredTheme, ThemeEntry } from '../../theme-entry.types.ts'\nimport type { ThemeMap } from '../../theme-map.types.ts'\nimport type { ThemeStore } from '../theme-store.types.ts'\n\nexport interface CookieThemeStoreOptions<Themes extends ThemeMap = ThemeMap> {\n\tcookieName: string\n\tpath?: string | undefined\n\tmaxAge?: number | undefined\n\tsameSite?: 'lax' | 'strict' | 'none' | undefined\n\tsecure?: boolean | undefined\n\tparse?: ParseStoredTheme<Themes> | undefined\n}\n\n/**\n * Creates a theme store backed by cookies.\n *\n * Persists across sessions. Cookies are sent with every request, so the server can\n * read the theme during SSR to avoid flash of wrong theme. Cross-tab sync is not\n * supported (cookies have no StorageEvent).\n *\n * @param themes - Record mapping theme keys to values (for validation)\n * @param options.cookieName - Cookie name for theme storage\n * @param options.path - Cookie path (default: '/')\n * @param options.maxAge - Cookie max-age in seconds\n * @param options.sameSite - Cookie sameSite attribute\n * @param options.secure - Cookie secure attribute\n * @param options.parse - Optional custom parser for stored string (default: parseStoredTheme)\n * @returns ThemeStore\n *\n * @example\n * ```ts\n * const themes = { current: 'theme-current', grayscale: 'theme-grayscale' }\n * const store = cookieThemeStore(themes, { cookieName: 'theme' })\n * store.read()\n * store.write(themeEntry(themes, 'grayscale'))\n * store.subscribe((themeResult) => {})\n * ```\n */\nexport function cookieThemeStore<Themes extends ThemeMap>(\n\tthemes: Themes,\n\toptions: CookieThemeStoreOptions<Themes>\n): Required<ThemeStore<Themes>> {\n\tconst { cookieName, path = '/', maxAge, sameSite, secure, parse = parseStoredTheme } = options\n\n\tif (document.cookie === undefined) {\n\t\treturn dummyThemeStore\n\t}\n\n\tconst handlers = new Set<(theme: ThemeEntry<Themes> | undefined) => void>()\n\tlet lastNotifiedKey: keyof Themes | undefined = read()?.theme ?? undefined\n\n\tfunction read() {\n\t\treturn readCookieTheme(themes, { cookieName, path, parse })\n\t}\n\n\tfunction notify() {\n\t\tconst result = read()\n\t\tconst key = result?.theme ?? undefined\n\t\tif (key === lastNotifiedKey) return\n\t\tlastNotifiedKey = key\n\t\tfor (const h of handlers) h(result)\n\t}\n\n\treturn {\n\t\tread,\n\t\twrite(entry) {\n\t\t\ttry {\n\t\t\t\twriteCookieTheme(themes, entry, {\n\t\t\t\t\tcookieName,\n\t\t\t\t\tpath,\n\t\t\t\t\tmaxAge,\n\t\t\t\t\tsameSite,\n\t\t\t\t\tsecure\n\t\t\t\t})\n\t\t\t\tnotify()\n\t\t\t} catch {\n\t\t\t\t// Ignore quota or other errors\n\t\t\t}\n\t\t},\n\t\tsubscribe(handler) {\n\t\t\thandlers.add(handler)\n\t\t\treturn () => {\n\t\t\t\thandlers.delete(handler)\n\t\t\t}\n\t\t}\n\t} satisfies ThemeStore<Themes>\n}\n\n/**\n * Reads the theme from cookies during SSR. Use with the request's Cookie header or\n * a framework's cookie API (e.g. Next.js cookies()).\n *\n * @param cookieSource - Raw Cookie header string, or a getter (name) => value for framework APIs\n * @param themes - Record mapping theme keys to values (for validation)\n * @param options - Optional cookie name (default: 'theme')\n * @returns ThemeEntry if valid cookie found, otherwise undefined\n *\n * @example\n * ```ts\n * // With raw Cookie header (Express, Remix, etc.)\n * const theme = getThemeFromCookie(request.headers.get('Cookie') ?? '', themes)\n *\n * // With Next.js cookies()\n * const theme = getThemeFromCookie(\n * (name) => cookies().get(name)?.value ?? undefined,\n * themes\n * )\n * ```\n */\nexport function getThemeFromCookie<Themes extends ThemeMap>(\n\tcookieSource: string | null | undefined | ((name: string) => string | null | undefined),\n\tthemes: Themes,\n\toptions: { cookieName?: string | undefined } = {}\n): ThemeEntry<Themes> | undefined {\n\tconst cookieName = options.cookieName ?? 'theme'\n\tconst stored =\n\t\ttypeof cookieSource === 'function'\n\t\t\t? (cookieSource(cookieName) ?? null)\n\t\t\t: cookieSource\n\t\t\t\t? getCookieFromHeader(cookieSource, cookieName)\n\t\t\t\t: null\n\treturn parseStoredTheme(themes, stored ?? undefined)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAgB,iBACf,QACA,SAC+B;CAC/B,MAAM,EAAE,YAAY,OAAO,KAAK,QAAQ,UAAU,QAAQ,QAAQA,gDAAqB;AAEvF,KAAI,SAAS,WAAW,OACvB,QAAOC;CAGR,MAAM,2BAAW,IAAI,KAAsD;CAC3E,IAAIC,kBAA4C,MAAM,EAAE,SAAS;CAEjE,SAAS,OAAO;AACf,SAAOC,0CAAgB,QAAQ;GAAE;GAAY;GAAM;GAAO,CAAC;;CAG5D,SAAS,SAAS;EACjB,MAAM,SAAS,MAAM;EACrB,MAAM,MAAM,QAAQ,SAAS;AAC7B,MAAI,QAAQ,gBAAiB;AAC7B,oBAAkB;AAClB,OAAK,MAAM,KAAK,SAAU,GAAE,OAAO;;AAGpC,QAAO;EACN;EACA,MAAM,OAAO;AACZ,OAAI;AACH,gDAAiB,QAAQ,OAAO;KAC/B;KACA;KACA;KACA;KACA;KACA,CAAC;AACF,YAAQ;WACD;;EAIT,UAAU,SAAS;AAClB,YAAS,IAAI,QAAQ;AACrB,gBAAa;AACZ,aAAS,OAAO,QAAQ;;;EAG1B;;;;;;;;;;;;;;;;;;;;;;;AAwBF,SAAgB,mBACf,cACA,QACA,UAA+C,EAAE,EAChB;CACjC,MAAM,aAAa,QAAQ,cAAc;AAOzC,QAAOH,4CAAiB,SALvB,OAAO,iBAAiB,aACpB,aAAa,WAAW,IAAI,OAC7B,eACCI,0CAAoB,cAAc,WAAW,GAC7C,SACqC,OAAU"}
@@ -1,15 +1,16 @@
1
1
  import { ThemeMap } from "../../theme-map.types.cjs";
2
- import { ThemeEntry } from "../../theme-entry.types.cjs";
2
+ import { ParseStoredTheme, ThemeEntry } from "../../theme-entry.types.cjs";
3
3
  import { ThemeStore } from "../theme-store.types.cjs";
4
4
  import { Required } from "type-plus";
5
5
 
6
6
  //#region src/theme/theme-store/cookie-theme-store/cookie-theme-store.d.ts
7
- interface CookieThemeStoreOptions {
7
+ interface CookieThemeStoreOptions<Themes extends ThemeMap = ThemeMap> {
8
8
  cookieName: string;
9
9
  path?: string | undefined;
10
10
  maxAge?: number | undefined;
11
11
  sameSite?: 'lax' | 'strict' | 'none' | undefined;
12
12
  secure?: boolean | undefined;
13
+ parse?: ParseStoredTheme<Themes> | undefined;
13
14
  }
14
15
  /**
15
16
  * Creates a theme store backed by cookies.
@@ -24,6 +25,7 @@ interface CookieThemeStoreOptions {
24
25
  * @param options.maxAge - Cookie max-age in seconds
25
26
  * @param options.sameSite - Cookie sameSite attribute
26
27
  * @param options.secure - Cookie secure attribute
28
+ * @param options.parse - Optional custom parser for stored string (default: parseStoredTheme)
27
29
  * @returns ThemeStore
28
30
  *
29
31
  * @example
@@ -35,7 +37,7 @@ interface CookieThemeStoreOptions {
35
37
  * store.subscribe((themeResult) => {})
36
38
  * ```
37
39
  */
38
- declare function cookieThemeStore<Themes extends ThemeMap>(themes: Themes, options: CookieThemeStoreOptions): Required<ThemeStore<Themes>>;
40
+ declare function cookieThemeStore<Themes extends ThemeMap>(themes: Themes, options: CookieThemeStoreOptions<Themes>): Required<ThemeStore<Themes>>;
39
41
  /**
40
42
  * Reads the theme from cookies during SSR. Use with the request's Cookie header or
41
43
  * a framework's cookie API (e.g. Next.js cookies()).
@@ -1 +1 @@
1
- {"version":3,"file":"cookie-theme-store.d.cts","names":[],"sources":["../../../../src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts"],"sourcesContent":[],"mappings":";;;;;;UAQiB,uBAAA;;EAAA,IAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EA+DD,MAAA,CAAA,EAAA,MAAA,GAAA,SAAgB;EAAgB,QAAA,CAAA,EAAA,KAAA,GAAA,QAAA,GAAA,MAAA,GAAA,SAAA;EACvC,MAAA,CAAA,EAAA,OAAA,GAAA,SAAA;;;;;;AAsFT;;;;;;;;;;;;;;;;;;;;iBAvFgB,gCAAgC,kBACvC,iBACC,0BACP,SAAS,WAAW;;;;;;;;;;;;;;;;;;;;;;iBAoFP,kCAAkC,2GAEzC;;IAEN,WAAW"}
1
+ {"version":3,"file":"cookie-theme-store.d.cts","names":[],"sources":["../../../../src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts"],"sourcesContent":[],"mappings":";;;;;;UAUiB,uCAAuC,WAAW;;EAAlD,IAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAuC,MAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAW,QAAA,CAAA,EAAA,KAAA,GAAA,QAAA,GAAA,MAAA,GAAA,SAAA;EAMzC,MAAA,CAAA,EAAA,OAAA,GAAA,SAAA;EAAjB,KAAA,CAAA,EAAA,gBAAA,CAAiB,MAAjB,CAAA,GAAA,SAAA;;AA4BT;;;;;;;;;AAuEA;;;;;;;;;;;;;;;;iBAvEgB,gCAAgC,kBACvC,iBACC,wBAAwB,UAC/B,SAAS,WAAW;;;;;;;;;;;;;;;;;;;;;;iBAoEP,kCAAkC,2GAEzC;;IAEN,WAAW"}
@@ -1,15 +1,16 @@
1
1
  import { ThemeMap } from "../../theme-map.types.mjs";
2
- import { ThemeEntry } from "../../theme-entry.types.mjs";
2
+ import { ParseStoredTheme, ThemeEntry } from "../../theme-entry.types.mjs";
3
3
  import { ThemeStore } from "../theme-store.types.mjs";
4
4
  import { Required } from "type-plus";
5
5
 
6
6
  //#region src/theme/theme-store/cookie-theme-store/cookie-theme-store.d.ts
7
- interface CookieThemeStoreOptions {
7
+ interface CookieThemeStoreOptions<Themes extends ThemeMap = ThemeMap> {
8
8
  cookieName: string;
9
9
  path?: string | undefined;
10
10
  maxAge?: number | undefined;
11
11
  sameSite?: 'lax' | 'strict' | 'none' | undefined;
12
12
  secure?: boolean | undefined;
13
+ parse?: ParseStoredTheme<Themes> | undefined;
13
14
  }
14
15
  /**
15
16
  * Creates a theme store backed by cookies.
@@ -24,6 +25,7 @@ interface CookieThemeStoreOptions {
24
25
  * @param options.maxAge - Cookie max-age in seconds
25
26
  * @param options.sameSite - Cookie sameSite attribute
26
27
  * @param options.secure - Cookie secure attribute
28
+ * @param options.parse - Optional custom parser for stored string (default: parseStoredTheme)
27
29
  * @returns ThemeStore
28
30
  *
29
31
  * @example
@@ -35,7 +37,7 @@ interface CookieThemeStoreOptions {
35
37
  * store.subscribe((themeResult) => {})
36
38
  * ```
37
39
  */
38
- declare function cookieThemeStore<Themes extends ThemeMap>(themes: Themes, options: CookieThemeStoreOptions): Required<ThemeStore<Themes>>;
40
+ declare function cookieThemeStore<Themes extends ThemeMap>(themes: Themes, options: CookieThemeStoreOptions<Themes>): Required<ThemeStore<Themes>>;
39
41
  /**
40
42
  * Reads the theme from cookies during SSR. Use with the request's Cookie header or
41
43
  * a framework's cookie API (e.g. Next.js cookies()).
@@ -1 +1 @@
1
- {"version":3,"file":"cookie-theme-store.d.mts","names":[],"sources":["../../../../src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts"],"sourcesContent":[],"mappings":";;;;;;UAQiB,uBAAA;;EAAA,IAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EA+DD,MAAA,CAAA,EAAA,MAAA,GAAA,SAAgB;EAAgB,QAAA,CAAA,EAAA,KAAA,GAAA,QAAA,GAAA,MAAA,GAAA,SAAA;EACvC,MAAA,CAAA,EAAA,OAAA,GAAA,SAAA;;;;;;AAsFT;;;;;;;;;;;;;;;;;;;;iBAvFgB,gCAAgC,kBACvC,iBACC,0BACP,SAAS,WAAW;;;;;;;;;;;;;;;;;;;;;;iBAoFP,kCAAkC,2GAEzC;;IAEN,WAAW"}
1
+ {"version":3,"file":"cookie-theme-store.d.mts","names":[],"sources":["../../../../src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts"],"sourcesContent":[],"mappings":";;;;;;UAUiB,uCAAuC,WAAW;;EAAlD,IAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAuC,MAAA,CAAA,EAAA,MAAA,GAAA,SAAA;EAAW,QAAA,CAAA,EAAA,KAAA,GAAA,QAAA,GAAA,MAAA,GAAA,SAAA;EAMzC,MAAA,CAAA,EAAA,OAAA,GAAA,SAAA;EAAjB,KAAA,CAAA,EAAA,gBAAA,CAAiB,MAAjB,CAAA,GAAA,SAAA;;AA4BT;;;;;;;;;AAuEA;;;;;;;;;;;;;;;;iBAvEgB,gCAAgC,kBACvC,iBACC,wBAAwB,UAC/B,SAAS,WAAW;;;;;;;;;;;;;;;;;;;;;;iBAoEP,kCAAkC,2GAEzC;;IAEN,WAAW"}
@@ -1,24 +1,10 @@
1
- import { themeEntry } from "../../theme-entry.mjs";
2
1
  import { dummyThemeStore } from "../../../testing/theme/dummy-theme-store.mjs";
3
2
  import { parseStoredTheme } from "../../_utils/parse-stored-theme.mjs";
3
+ import { getCookieFromHeader } from "../../cookie/_cookie-utils.mjs";
4
+ import { readCookieTheme } from "../../cookie/read-cookie-theme.mjs";
5
+ import { writeCookieTheme } from "../../cookie/write-cookie-theme.mjs";
4
6
 
5
7
  //#region src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts
6
- function getCookieValue(name) {
7
- if (typeof document === "undefined" || !document.cookie) return null;
8
- const value = document.cookie.match(/* @__PURE__ */ new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))?.[1];
9
- return value !== void 0 ? decodeURIComponent(value) : null;
10
- }
11
- function setCookie(name, value, options) {
12
- const parts = [`${name}=${encodeURIComponent(value)}`];
13
- parts.push(`path=${options.path ?? "/"}`);
14
- if (options.maxAge !== void 0) parts.push(`max-age=${options.maxAge}`);
15
- if (options.sameSite !== void 0) parts.push(`samesite=${options.sameSite}`);
16
- if (options.secure) parts.push("secure");
17
- document.cookie = parts.join("; ");
18
- }
19
- function deleteCookie(name, path = "/") {
20
- document.cookie = `${name}=; path=${path}; max-age=0`;
21
- }
22
8
  /**
23
9
  * Creates a theme store backed by cookies.
24
10
  *
@@ -32,6 +18,7 @@ function deleteCookie(name, path = "/") {
32
18
  * @param options.maxAge - Cookie max-age in seconds
33
19
  * @param options.sameSite - Cookie sameSite attribute
34
20
  * @param options.secure - Cookie secure attribute
21
+ * @param options.parse - Optional custom parser for stored string (default: parseStoredTheme)
35
22
  * @returns ThemeStore
36
23
  *
37
24
  * @example
@@ -44,14 +31,16 @@ function deleteCookie(name, path = "/") {
44
31
  * ```
45
32
  */
46
33
  function cookieThemeStore(themes, options) {
47
- const { cookieName, path = "/", maxAge, sameSite, secure } = options;
34
+ const { cookieName, path = "/", maxAge, sameSite, secure, parse = parseStoredTheme } = options;
48
35
  if (document.cookie === void 0) return dummyThemeStore;
49
36
  const handlers = /* @__PURE__ */ new Set();
50
37
  let lastNotifiedKey = read()?.theme ?? void 0;
51
38
  function read() {
52
- const theme = parseStoredTheme(themes, getCookieValue(cookieName));
53
- if (theme === void 0) return void 0;
54
- return themeEntry(themes, theme);
39
+ return readCookieTheme(themes, {
40
+ cookieName,
41
+ path,
42
+ parse
43
+ });
55
44
  }
56
45
  function notify() {
57
46
  const result = read();
@@ -64,14 +53,13 @@ function cookieThemeStore(themes, options) {
64
53
  read,
65
54
  write(entry) {
66
55
  try {
67
- if (entry === void 0) deleteCookie(cookieName, path);
68
- else {
69
- const opts = { path };
70
- if (maxAge !== void 0) opts.maxAge = maxAge;
71
- if (sameSite !== void 0) opts.sameSite = sameSite;
72
- if (secure) opts.secure = true;
73
- setCookie(cookieName, JSON.stringify(entry), opts);
74
- }
56
+ writeCookieTheme(themes, entry, {
57
+ cookieName,
58
+ path,
59
+ maxAge,
60
+ sameSite,
61
+ secure
62
+ });
75
63
  notify();
76
64
  } catch {}
77
65
  },
@@ -83,10 +71,6 @@ function cookieThemeStore(themes, options) {
83
71
  }
84
72
  };
85
73
  }
86
- function getCookieFromHeader(cookieHeader, name) {
87
- const value = cookieHeader.match(/* @__PURE__ */ new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))?.[1];
88
- return value !== void 0 ? decodeURIComponent(value.trim()) : null;
89
- }
90
74
  /**
91
75
  * Reads the theme from cookies during SSR. Use with the request's Cookie header or
92
76
  * a framework's cookie API (e.g. Next.js cookies()).
@@ -110,9 +94,7 @@ function getCookieFromHeader(cookieHeader, name) {
110
94
  */
111
95
  function getThemeFromCookie(cookieSource, themes, options = {}) {
112
96
  const cookieName = options.cookieName ?? "theme";
113
- const theme = parseStoredTheme(themes, typeof cookieSource === "function" ? cookieSource(cookieName) ?? null : cookieSource ? getCookieFromHeader(cookieSource, cookieName) : null);
114
- if (theme === void 0) return void 0;
115
- return themeEntry(themes, theme);
97
+ return parseStoredTheme(themes, (typeof cookieSource === "function" ? cookieSource(cookieName) ?? null : cookieSource ? getCookieFromHeader(cookieSource, cookieName) : null) ?? void 0);
116
98
  }
117
99
 
118
100
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"cookie-theme-store.mjs","names":["lastNotifiedKey: keyof Themes | undefined","opts: {\n\t\t\t\t\t\tpath: string\n\t\t\t\t\t\tmaxAge?: number\n\t\t\t\t\t\tsameSite?: 'lax' | 'strict' | 'none'\n\t\t\t\t\t\tsecure?: boolean\n\t\t\t\t\t}"],"sources":["../../../../src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts"],"sourcesContent":["import type { Required } from 'type-plus'\nimport { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'\nimport { parseStoredTheme } from '../../_utils/parse-stored-theme.ts'\nimport { themeEntry } from '../../theme-entry.ts'\nimport type { ThemeEntry } from '../../theme-entry.types.ts'\nimport type { ThemeMap } from '../../theme-map.types.ts'\nimport type { ThemeStore } from '../theme-store.types.ts'\n\nexport interface CookieThemeStoreOptions {\n\tcookieName: string\n\tpath?: string | undefined\n\tmaxAge?: number | undefined\n\tsameSite?: 'lax' | 'strict' | 'none' | undefined\n\tsecure?: boolean | undefined\n}\n\nfunction getCookieValue(name: string): string | null {\n\tif (typeof document === 'undefined' || !document.cookie) return null\n\tconst match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`))\n\tconst value = match?.[1]\n\treturn value !== undefined ? decodeURIComponent(value) : null\n}\n\nfunction setCookie(\n\tname: string,\n\tvalue: string,\n\toptions: {\n\t\tpath?: string | undefined\n\t\tmaxAge?: number | undefined\n\t\tsameSite?: 'lax' | 'strict' | 'none' | undefined\n\t\tsecure?: boolean | undefined\n\t}\n) {\n\tconst parts = [`${name}=${encodeURIComponent(value)}`]\n\tparts.push(`path=${options.path ?? '/'}`)\n\tif (options.maxAge !== undefined) parts.push(`max-age=${options.maxAge}`)\n\tif (options.sameSite !== undefined) parts.push(`samesite=${options.sameSite}`)\n\tif (options.secure) parts.push('secure')\n\t// biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API has limited support; document.cookie is standard for theme persistence\n\tdocument.cookie = parts.join('; ')\n}\n\nfunction deleteCookie(name: string, path = '/') {\n\t// biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API has limited support; document.cookie is standard for theme persistence\n\tdocument.cookie = `${name}=; path=${path}; max-age=0`\n}\n\n/**\n * Creates a theme store backed by cookies.\n *\n * Persists across sessions. Cookies are sent with every request, so the server can\n * read the theme during SSR to avoid flash of wrong theme. Cross-tab sync is not\n * supported (cookies have no StorageEvent).\n *\n * @param themes - Record mapping theme keys to values (for validation)\n * @param options.cookieName - Cookie name for theme storage\n * @param options.path - Cookie path (default: '/')\n * @param options.maxAge - Cookie max-age in seconds\n * @param options.sameSite - Cookie sameSite attribute\n * @param options.secure - Cookie secure attribute\n * @returns ThemeStore\n *\n * @example\n * ```ts\n * const themes = { current: 'theme-current', grayscale: 'theme-grayscale' }\n * const store = cookieThemeStore(themes, { cookieName: 'theme' })\n * store.read()\n * store.write(themeEntry(themes, 'grayscale'))\n * store.subscribe((themeResult) => {})\n * ```\n */\nexport function cookieThemeStore<Themes extends ThemeMap>(\n\tthemes: Themes,\n\toptions: CookieThemeStoreOptions\n): Required<ThemeStore<Themes>> {\n\tconst { cookieName, path = '/', maxAge, sameSite, secure } = options\n\n\tif (document.cookie === undefined) {\n\t\treturn dummyThemeStore\n\t}\n\n\tconst handlers = new Set<(theme: ThemeEntry<Themes> | undefined) => void>()\n\tlet lastNotifiedKey: keyof Themes | undefined = read()?.theme ?? undefined\n\n\tfunction read() {\n\t\tconst stored = getCookieValue(cookieName)\n\t\tconst theme = parseStoredTheme(themes, stored)\n\t\tif (theme === undefined) return undefined\n\t\treturn themeEntry(themes, theme)\n\t}\n\n\tfunction notify() {\n\t\tconst result = read()\n\t\tconst key = result?.theme ?? undefined\n\t\tif (key === lastNotifiedKey) return\n\t\tlastNotifiedKey = key\n\t\tfor (const h of handlers) h(result)\n\t}\n\n\treturn {\n\t\tread,\n\t\twrite(entry) {\n\t\t\ttry {\n\t\t\t\tif (entry === undefined) {\n\t\t\t\t\tdeleteCookie(cookieName, path)\n\t\t\t\t} else {\n\t\t\t\t\tconst opts: {\n\t\t\t\t\t\tpath: string\n\t\t\t\t\t\tmaxAge?: number\n\t\t\t\t\t\tsameSite?: 'lax' | 'strict' | 'none'\n\t\t\t\t\t\tsecure?: boolean\n\t\t\t\t\t} = { path }\n\t\t\t\t\tif (maxAge !== undefined) opts.maxAge = maxAge\n\t\t\t\t\tif (sameSite !== undefined) opts.sameSite = sameSite\n\t\t\t\t\tif (secure) opts.secure = true\n\t\t\t\t\tsetCookie(cookieName, JSON.stringify(entry), opts)\n\t\t\t\t}\n\t\t\t\tnotify()\n\t\t\t} catch {\n\t\t\t\t// Ignore quota or other errors\n\t\t\t}\n\t\t},\n\t\tsubscribe(handler) {\n\t\t\thandlers.add(handler)\n\t\t\treturn () => {\n\t\t\t\thandlers.delete(handler)\n\t\t\t}\n\t\t}\n\t} satisfies ThemeStore<Themes>\n}\n\nfunction getCookieFromHeader(cookieHeader: string, name: string): string | null {\n\tconst match = cookieHeader.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`))\n\tconst value = match?.[1]\n\treturn value !== undefined ? decodeURIComponent(value.trim()) : null\n}\n\n/**\n * Reads the theme from cookies during SSR. Use with the request's Cookie header or\n * a framework's cookie API (e.g. Next.js cookies()).\n *\n * @param cookieSource - Raw Cookie header string, or a getter (name) => value for framework APIs\n * @param themes - Record mapping theme keys to values (for validation)\n * @param options - Optional cookie name (default: 'theme')\n * @returns ThemeEntry if valid cookie found, otherwise undefined\n *\n * @example\n * ```ts\n * // With raw Cookie header (Express, Remix, etc.)\n * const theme = getThemeFromCookie(request.headers.get('Cookie') ?? '', themes)\n *\n * // With Next.js cookies()\n * const theme = getThemeFromCookie(\n * (name) => cookies().get(name)?.value ?? undefined,\n * themes\n * )\n * ```\n */\nexport function getThemeFromCookie<Themes extends ThemeMap>(\n\tcookieSource: string | null | undefined | ((name: string) => string | null | undefined),\n\tthemes: Themes,\n\toptions: { cookieName?: string | undefined } = {}\n): ThemeEntry<Themes> | undefined {\n\tconst cookieName = options.cookieName ?? 'theme'\n\tconst stored =\n\t\ttypeof cookieSource === 'function'\n\t\t\t? (cookieSource(cookieName) ?? null)\n\t\t\t: cookieSource\n\t\t\t\t? getCookieFromHeader(cookieSource, cookieName)\n\t\t\t\t: null\n\tconst theme = parseStoredTheme(themes, stored)\n\tif (theme === undefined) return undefined\n\treturn themeEntry(themes, theme)\n}\n"],"mappings":";;;;;AAgBA,SAAS,eAAe,MAA6B;AACpD,KAAI,OAAO,aAAa,eAAe,CAAC,SAAS,OAAQ,QAAO;CAEhE,MAAM,QADQ,SAAS,OAAO,sBAAM,IAAI,OAAO,cAAc,KAAK,UAAU,CAAC,GACvD;AACtB,QAAO,UAAU,SAAY,mBAAmB,MAAM,GAAG;;AAG1D,SAAS,UACR,MACA,OACA,SAMC;CACD,MAAM,QAAQ,CAAC,GAAG,KAAK,GAAG,mBAAmB,MAAM,GAAG;AACtD,OAAM,KAAK,QAAQ,QAAQ,QAAQ,MAAM;AACzC,KAAI,QAAQ,WAAW,OAAW,OAAM,KAAK,WAAW,QAAQ,SAAS;AACzE,KAAI,QAAQ,aAAa,OAAW,OAAM,KAAK,YAAY,QAAQ,WAAW;AAC9E,KAAI,QAAQ,OAAQ,OAAM,KAAK,SAAS;AAExC,UAAS,SAAS,MAAM,KAAK,KAAK;;AAGnC,SAAS,aAAa,MAAc,OAAO,KAAK;AAE/C,UAAS,SAAS,GAAG,KAAK,UAAU,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;AA2B1C,SAAgB,iBACf,QACA,SAC+B;CAC/B,MAAM,EAAE,YAAY,OAAO,KAAK,QAAQ,UAAU,WAAW;AAE7D,KAAI,SAAS,WAAW,OACvB,QAAO;CAGR,MAAM,2BAAW,IAAI,KAAsD;CAC3E,IAAIA,kBAA4C,MAAM,EAAE,SAAS;CAEjE,SAAS,OAAO;EAEf,MAAM,QAAQ,iBAAiB,QADhB,eAAe,WAAW,CACK;AAC9C,MAAI,UAAU,OAAW,QAAO;AAChC,SAAO,WAAW,QAAQ,MAAM;;CAGjC,SAAS,SAAS;EACjB,MAAM,SAAS,MAAM;EACrB,MAAM,MAAM,QAAQ,SAAS;AAC7B,MAAI,QAAQ,gBAAiB;AAC7B,oBAAkB;AAClB,OAAK,MAAM,KAAK,SAAU,GAAE,OAAO;;AAGpC,QAAO;EACN;EACA,MAAM,OAAO;AACZ,OAAI;AACH,QAAI,UAAU,OACb,cAAa,YAAY,KAAK;SACxB;KACN,MAAMC,OAKF,EAAE,MAAM;AACZ,SAAI,WAAW,OAAW,MAAK,SAAS;AACxC,SAAI,aAAa,OAAW,MAAK,WAAW;AAC5C,SAAI,OAAQ,MAAK,SAAS;AAC1B,eAAU,YAAY,KAAK,UAAU,MAAM,EAAE,KAAK;;AAEnD,YAAQ;WACD;;EAIT,UAAU,SAAS;AAClB,YAAS,IAAI,QAAQ;AACrB,gBAAa;AACZ,aAAS,OAAO,QAAQ;;;EAG1B;;AAGF,SAAS,oBAAoB,cAAsB,MAA6B;CAE/E,MAAM,QADQ,aAAa,sBAAM,IAAI,OAAO,cAAc,KAAK,UAAU,CAAC,GACpD;AACtB,QAAO,UAAU,SAAY,mBAAmB,MAAM,MAAM,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;AAwBjE,SAAgB,mBACf,cACA,QACA,UAA+C,EAAE,EAChB;CACjC,MAAM,aAAa,QAAQ,cAAc;CAOzC,MAAM,QAAQ,iBAAiB,QAL9B,OAAO,iBAAiB,aACpB,aAAa,WAAW,IAAI,OAC7B,eACC,oBAAoB,cAAc,WAAW,GAC7C,KACyC;AAC9C,KAAI,UAAU,OAAW,QAAO;AAChC,QAAO,WAAW,QAAQ,MAAM"}
1
+ {"version":3,"file":"cookie-theme-store.mjs","names":["lastNotifiedKey: keyof Themes | undefined"],"sources":["../../../../src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts"],"sourcesContent":["import type { Required } from 'type-plus'\nimport { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'\nimport { parseStoredTheme } from '../../_utils/parse-stored-theme.ts'\nimport { getCookieFromHeader } from '../../cookie/_cookie-utils.ts'\nimport { readCookieTheme } from '../../cookie/read-cookie-theme.ts'\nimport { writeCookieTheme } from '../../cookie/write-cookie-theme.ts'\nimport type { ParseStoredTheme, ThemeEntry } from '../../theme-entry.types.ts'\nimport type { ThemeMap } from '../../theme-map.types.ts'\nimport type { ThemeStore } from '../theme-store.types.ts'\n\nexport interface CookieThemeStoreOptions<Themes extends ThemeMap = ThemeMap> {\n\tcookieName: string\n\tpath?: string | undefined\n\tmaxAge?: number | undefined\n\tsameSite?: 'lax' | 'strict' | 'none' | undefined\n\tsecure?: boolean | undefined\n\tparse?: ParseStoredTheme<Themes> | undefined\n}\n\n/**\n * Creates a theme store backed by cookies.\n *\n * Persists across sessions. Cookies are sent with every request, so the server can\n * read the theme during SSR to avoid flash of wrong theme. Cross-tab sync is not\n * supported (cookies have no StorageEvent).\n *\n * @param themes - Record mapping theme keys to values (for validation)\n * @param options.cookieName - Cookie name for theme storage\n * @param options.path - Cookie path (default: '/')\n * @param options.maxAge - Cookie max-age in seconds\n * @param options.sameSite - Cookie sameSite attribute\n * @param options.secure - Cookie secure attribute\n * @param options.parse - Optional custom parser for stored string (default: parseStoredTheme)\n * @returns ThemeStore\n *\n * @example\n * ```ts\n * const themes = { current: 'theme-current', grayscale: 'theme-grayscale' }\n * const store = cookieThemeStore(themes, { cookieName: 'theme' })\n * store.read()\n * store.write(themeEntry(themes, 'grayscale'))\n * store.subscribe((themeResult) => {})\n * ```\n */\nexport function cookieThemeStore<Themes extends ThemeMap>(\n\tthemes: Themes,\n\toptions: CookieThemeStoreOptions<Themes>\n): Required<ThemeStore<Themes>> {\n\tconst { cookieName, path = '/', maxAge, sameSite, secure, parse = parseStoredTheme } = options\n\n\tif (document.cookie === undefined) {\n\t\treturn dummyThemeStore\n\t}\n\n\tconst handlers = new Set<(theme: ThemeEntry<Themes> | undefined) => void>()\n\tlet lastNotifiedKey: keyof Themes | undefined = read()?.theme ?? undefined\n\n\tfunction read() {\n\t\treturn readCookieTheme(themes, { cookieName, path, parse })\n\t}\n\n\tfunction notify() {\n\t\tconst result = read()\n\t\tconst key = result?.theme ?? undefined\n\t\tif (key === lastNotifiedKey) return\n\t\tlastNotifiedKey = key\n\t\tfor (const h of handlers) h(result)\n\t}\n\n\treturn {\n\t\tread,\n\t\twrite(entry) {\n\t\t\ttry {\n\t\t\t\twriteCookieTheme(themes, entry, {\n\t\t\t\t\tcookieName,\n\t\t\t\t\tpath,\n\t\t\t\t\tmaxAge,\n\t\t\t\t\tsameSite,\n\t\t\t\t\tsecure\n\t\t\t\t})\n\t\t\t\tnotify()\n\t\t\t} catch {\n\t\t\t\t// Ignore quota or other errors\n\t\t\t}\n\t\t},\n\t\tsubscribe(handler) {\n\t\t\thandlers.add(handler)\n\t\t\treturn () => {\n\t\t\t\thandlers.delete(handler)\n\t\t\t}\n\t\t}\n\t} satisfies ThemeStore<Themes>\n}\n\n/**\n * Reads the theme from cookies during SSR. Use with the request's Cookie header or\n * a framework's cookie API (e.g. Next.js cookies()).\n *\n * @param cookieSource - Raw Cookie header string, or a getter (name) => value for framework APIs\n * @param themes - Record mapping theme keys to values (for validation)\n * @param options - Optional cookie name (default: 'theme')\n * @returns ThemeEntry if valid cookie found, otherwise undefined\n *\n * @example\n * ```ts\n * // With raw Cookie header (Express, Remix, etc.)\n * const theme = getThemeFromCookie(request.headers.get('Cookie') ?? '', themes)\n *\n * // With Next.js cookies()\n * const theme = getThemeFromCookie(\n * (name) => cookies().get(name)?.value ?? undefined,\n * themes\n * )\n * ```\n */\nexport function getThemeFromCookie<Themes extends ThemeMap>(\n\tcookieSource: string | null | undefined | ((name: string) => string | null | undefined),\n\tthemes: Themes,\n\toptions: { cookieName?: string | undefined } = {}\n): ThemeEntry<Themes> | undefined {\n\tconst cookieName = options.cookieName ?? 'theme'\n\tconst stored =\n\t\ttypeof cookieSource === 'function'\n\t\t\t? (cookieSource(cookieName) ?? null)\n\t\t\t: cookieSource\n\t\t\t\t? getCookieFromHeader(cookieSource, cookieName)\n\t\t\t\t: null\n\treturn parseStoredTheme(themes, stored ?? undefined)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAgB,iBACf,QACA,SAC+B;CAC/B,MAAM,EAAE,YAAY,OAAO,KAAK,QAAQ,UAAU,QAAQ,QAAQ,qBAAqB;AAEvF,KAAI,SAAS,WAAW,OACvB,QAAO;CAGR,MAAM,2BAAW,IAAI,KAAsD;CAC3E,IAAIA,kBAA4C,MAAM,EAAE,SAAS;CAEjE,SAAS,OAAO;AACf,SAAO,gBAAgB,QAAQ;GAAE;GAAY;GAAM;GAAO,CAAC;;CAG5D,SAAS,SAAS;EACjB,MAAM,SAAS,MAAM;EACrB,MAAM,MAAM,QAAQ,SAAS;AAC7B,MAAI,QAAQ,gBAAiB;AAC7B,oBAAkB;AAClB,OAAK,MAAM,KAAK,SAAU,GAAE,OAAO;;AAGpC,QAAO;EACN;EACA,MAAM,OAAO;AACZ,OAAI;AACH,qBAAiB,QAAQ,OAAO;KAC/B;KACA;KACA;KACA;KACA;KACA,CAAC;AACF,YAAQ;WACD;;EAIT,UAAU,SAAS;AAClB,YAAS,IAAI,QAAQ;AACrB,gBAAa;AACZ,aAAS,OAAO,QAAQ;;;EAG1B;;;;;;;;;;;;;;;;;;;;;;;AAwBF,SAAgB,mBACf,cACA,QACA,UAA+C,EAAE,EAChB;CACjC,MAAM,aAAa,QAAQ,cAAc;AAOzC,QAAO,iBAAiB,SALvB,OAAO,iBAAiB,aACpB,aAAa,WAAW,IAAI,OAC7B,eACC,oBAAoB,cAAc,WAAW,GAC7C,SACqC,OAAU"}
@@ -1,47 +1,67 @@
1
- const require_get_data_attribute = require('../../../attributes/get-data-attribute.cjs');
2
- const require_observe_data_attribute = require('../../../attributes/observe-data-attribute.cjs');
3
- const require_theme_entry = require('../../theme-entry.cjs');
4
- const require_dummy_theme_store = require('../../../testing/theme/dummy-theme-store.cjs');
5
- const require_resolve_theme_from_data_attribute = require('../../data-attribute/resolve-theme-from-data-attribute.cjs');
6
- const require_apply_theme_to_data_attribute = require('../../data-attribute/apply-theme-to-data-attribute.cjs');
1
+ const require__constant = require('../../data-attribute/_constant.cjs');
2
+ const require_parse_data_attribute = require('../../data-attribute/parse-data-attribute.cjs');
3
+ const require_read_data_attribute = require('../../data-attribute/read-data-attribute.cjs');
4
+ const require_stringify_data_attribute = require('../../data-attribute/stringify-data-attribute.cjs');
5
+ const require_subscribe_data_attribute = require('../../data-attribute/subscribe-data-attribute.cjs');
6
+ const require_write_data_attribute = require('../../data-attribute/write-data-attribute.cjs');
7
7
 
8
8
  //#region src/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.ts
9
9
  /**
10
10
  * Creates a theme store that reads and writes via a data attribute.
11
11
  *
12
+ * read: parse(themes, getDataAttribute(element, attribute)) → ThemeEntry
13
+ * write: setAttribute(attribute, stringify(themes, getDataAttribute(element, attribute), entry))
14
+ *
15
+ * Supports space-separated attribute values by default. Use `parse` and `stringify` to customize
16
+ * (e.g. comma-separated via curried parseDataAttribute/stringifyDataAttribute).
17
+ *
12
18
  * @param themes - Record mapping theme keys to attribute values
13
19
  * @param options.attributeName - Data attribute name (e.g. `data-theme`)
14
- * @param options.element - Element to operate on (defaults to document.documentElement)
20
+ * @param options.element - Element to operate on (accepts null e.g. from refs). Defaults to document.documentElement.
21
+ * @param options.parse - Custom parser (default: parseDataAttribute with space separator)
22
+ * @param options.stringify - Custom serializer (default: stringifyDataAttribute with space separator)
15
23
  * @returns ThemeStore
16
24
  *
17
25
  * @example
18
26
  * ```ts
19
27
  * const themes = { current: 'current', grayscale: 'grayscale' }
20
28
  * const store = dataAttributeThemeStore(themes, { attributeName: 'data-theme' })
21
- * store.read() // returns themeResult from data attribute
29
+ * store.read() // returns ThemeEntry from data attribute
22
30
  * store.write(themeEntry(themes, 'grayscale'))
23
- * store.subscribe((themeResult) => {})
31
+ * store.subscribe((entry) => {})
32
+ * ```
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * // Comma-separated
37
+ * const store = dataAttributeThemeStore(themes, {
38
+ * attributeName: 'data-theme',
39
+ * parse: (t, v) => parseDataAttribute(t, v, { separator: ',' }),
40
+ * stringify: (t, x, e) => stringifyDataAttribute(t, x, e, { separator: ',' })
41
+ * })
24
42
  * ```
25
43
  */
26
44
  function dataAttributeThemeStore(themes, options) {
27
45
  const element = options.element ?? document?.documentElement;
28
- const { attributeName } = options;
29
- if (!element) return require_dummy_theme_store.dummyThemeStore;
46
+ const { attributeName, parse = (t, v) => require_parse_data_attribute.parseDataAttribute(t, v, { separator: require__constant.SEPARATOR_SPACE }), stringify = (t, x, e) => require_stringify_data_attribute.stringifyDataAttribute(t, x, e, { separator: require__constant.SEPARATOR_SPACE }) } = options;
30
47
  return {
31
48
  read() {
32
- const theme = require_resolve_theme_from_data_attribute.resolveThemeFromDataAttribute(themes, require_get_data_attribute.getDataAttribute(attributeName, element));
33
- if (theme === void 0) return void 0;
34
- return require_theme_entry.themeEntry(themes, theme);
49
+ return require_read_data_attribute.readDataAttribute(themes, attributeName, {
50
+ element,
51
+ parse
52
+ });
35
53
  },
36
54
  write(entry) {
37
- require_apply_theme_to_data_attribute.applyThemeToDataAttribute(element, attributeName, entry);
55
+ require_write_data_attribute.writeDataAttribute(themes, attributeName, entry, {
56
+ element,
57
+ stringify
58
+ });
38
59
  },
39
60
  subscribe(handler) {
40
- const observer = require_observe_data_attribute.observeDataAttributes({ [attributeName]: (value) => {
41
- const theme = value ? require_resolve_theme_from_data_attribute.resolveThemeFromDataAttribute(themes, value) : void 0;
42
- handler(theme ? require_theme_entry.themeEntry(themes, theme) : void 0);
43
- } }, element);
44
- return () => observer.disconnect();
61
+ return require_subscribe_data_attribute.subscribeDataAttribute(themes, attributeName, handler, {
62
+ element,
63
+ parse
64
+ });
45
65
  }
46
66
  };
47
67
  }