@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
@@ -0,0 +1,31 @@
1
+ import type { StringifyStoredTheme, ThemeEntry } from '../theme-entry.types.ts'
2
+ import type { ThemeMap } from '../theme-map.types.ts'
3
+ import { writeWebStorage } from '../web-storage/write-web-storage.ts'
4
+
5
+ /**
6
+ * Writes a theme entry to localStorage.
7
+ *
8
+ * Performs setItem/removeItem only. Does not notify subscribers; the store must call notify() after this.
9
+ *
10
+ * @param themes - Record mapping theme keys to values (used by stringify)
11
+ * @param storageKey - localStorage key to write to
12
+ * @param entry - Theme entry to write, or null/undefined to remove
13
+ * @param options.stringify - Custom serializer (default: JSON.stringify)
14
+ * @param options.onError - Optional callback invoked when storage write throws
15
+ */
16
+ export function writeLocalStorage<Themes extends ThemeMap>(
17
+ themes: Themes,
18
+ storageKey: string,
19
+ entry: ThemeEntry<Themes> | null | undefined,
20
+ options?: {
21
+ stringify?: StringifyStoredTheme<Themes> | undefined
22
+ onError?: ((error: unknown) => void) | undefined
23
+ }
24
+ ): void {
25
+ if (!window?.localStorage) return
26
+ writeWebStorage(themes, storageKey, entry, {
27
+ storage: window.localStorage,
28
+ stringify: options?.stringify,
29
+ onError: options?.onError
30
+ })
31
+ }
@@ -0,0 +1,30 @@
1
+ import { getPrefersColorScheme } from '../../color-scheme/get-prefers-color-scheme.ts'
2
+ import { themeEntry } from '../theme-entry.ts'
3
+ import type { ThemeEntry } from '../theme-entry.types.ts'
4
+
5
+ type PrefersColorSchemeThemes = {
6
+ light: string | readonly string[]
7
+ dark: string | readonly string[]
8
+ }
9
+
10
+ export interface ReadPrefersColorSchemeThemeOptions {
11
+ defaultColorScheme?: 'light' | 'dark' | undefined
12
+ }
13
+
14
+ /**
15
+ * Reads a theme entry from the system `prefers-color-scheme` media query.
16
+ *
17
+ * Themes must only include `light` and `dark` keys—this mirrors the system preference.
18
+ *
19
+ * @param themes - Record with `light` and `dark` keys mapping to theme values
20
+ * @param options.defaultColorScheme - Fallback when matchMedia is unavailable (e.g. SSR, default: 'light')
21
+ * @returns ThemeEntry for current system preference
22
+ */
23
+ export function readPrefersColorSchemeTheme<Themes extends PrefersColorSchemeThemes>(
24
+ themes: Themes,
25
+ options?: ReadPrefersColorSchemeThemeOptions | undefined
26
+ ): ThemeEntry<Themes> {
27
+ const defaultColorScheme = options?.defaultColorScheme ?? 'light'
28
+ const scheme = getPrefersColorScheme(defaultColorScheme)
29
+ return themeEntry(themes, scheme)
30
+ }
@@ -0,0 +1,24 @@
1
+ import { observePrefersColorScheme } from '../../color-scheme/observe-prefers-color-scheme.ts'
2
+ import { themeEntry } from '../theme-entry.ts'
3
+ import type { ThemeEntry } from '../theme-entry.types.ts'
4
+
5
+ type PrefersColorSchemeThemes = {
6
+ light: string | readonly string[]
7
+ dark: string | readonly string[]
8
+ }
9
+
10
+ /**
11
+ * Subscribes to system `prefers-color-scheme` changes and invokes the handler with theme entries.
12
+ *
13
+ * Themes must only include `light` and `dark` keys—this mirrors the system preference.
14
+ *
15
+ * @param themes - Record with `light` and `dark` keys mapping to theme values
16
+ * @param handler - Callback invoked when the color scheme preference changes
17
+ * @returns Unsubscribe function
18
+ */
19
+ export function subscribePrefersColorSchemeTheme<Themes extends PrefersColorSchemeThemes>(
20
+ themes: Themes,
21
+ handler: (entry: ThemeEntry<Themes>) => void
22
+ ): () => void {
23
+ return observePrefersColorScheme((scheme) => handler(themeEntry(themes, scheme)))
24
+ }
@@ -0,0 +1,23 @@
1
+ import type { ParseStoredTheme, ThemeEntry } from '../theme-entry.types.ts'
2
+ import type { ThemeMap } from '../theme-map.types.ts'
3
+ import { readWebStorage } from '../web-storage/read-web-storage.ts'
4
+
5
+ /**
6
+ * Reads a theme entry from sessionStorage.
7
+ *
8
+ * @param themes - Record mapping theme keys to values (for validation)
9
+ * @param storageKey - sessionStorage key to read from
10
+ * @param options.parse - Custom parser (default: parseStoredTheme)
11
+ * @returns ThemeEntry if found, undefined otherwise. Returns undefined when sessionStorage is unavailable (e.g. SSR).
12
+ */
13
+ export function readSessionStorage<Themes extends ThemeMap>(
14
+ themes: Themes,
15
+ storageKey: string,
16
+ options?: { parse?: ParseStoredTheme<Themes> | undefined }
17
+ ): ThemeEntry<Themes> | undefined {
18
+ if (!window?.sessionStorage) return undefined
19
+ return readWebStorage(themes, storageKey, {
20
+ storage: window.sessionStorage,
21
+ parse: options?.parse
22
+ })
23
+ }
@@ -0,0 +1,31 @@
1
+ import type { StringifyStoredTheme, ThemeEntry } from '../theme-entry.types.ts'
2
+ import type { ThemeMap } from '../theme-map.types.ts'
3
+ import { writeWebStorage } from '../web-storage/write-web-storage.ts'
4
+
5
+ /**
6
+ * Writes a theme entry to sessionStorage.
7
+ *
8
+ * Performs setItem/removeItem only. Does not notify subscribers; the store must call notify() after this.
9
+ *
10
+ * @param themes - Record mapping theme keys to values (used by stringify)
11
+ * @param storageKey - sessionStorage key to write to
12
+ * @param entry - Theme entry to write, or null/undefined to remove
13
+ * @param options.stringify - Custom serializer (default: JSON.stringify)
14
+ * @param options.onError - Optional callback invoked when storage write throws
15
+ */
16
+ export function writeSessionStorage<Themes extends ThemeMap>(
17
+ themes: Themes,
18
+ storageKey: string,
19
+ entry: ThemeEntry<Themes> | null | undefined,
20
+ options?: {
21
+ stringify?: StringifyStoredTheme<Themes> | undefined
22
+ onError?: ((error: unknown) => void) | undefined
23
+ }
24
+ ): void {
25
+ if (!window?.sessionStorage) return
26
+ writeWebStorage(themes, storageKey, entry, {
27
+ storage: window.sessionStorage,
28
+ stringify: options?.stringify,
29
+ onError: options?.onError
30
+ })
31
+ }
@@ -9,3 +9,24 @@ export interface ThemeEntry<Themes extends ThemeMap = ThemeMap> {
9
9
  theme: keyof Themes
10
10
  value: Themes[keyof Themes]
11
11
  }
12
+
13
+ /**
14
+ * Function type for parsing stored string into ThemeEntry.
15
+ * Used as options.parse in persisting theme stores.
16
+ * Value accepts null (e.g. from getItem, getAttribute, cookie parsing).
17
+ */
18
+ export type ParseStoredTheme<Themes extends ThemeMap> = (
19
+ themes: Themes,
20
+ value: string | null | undefined
21
+ ) => ThemeEntry<Themes> | undefined
22
+
23
+ /**
24
+ * Function type for stringify ThemeEntry to a stored string.
25
+ * Used as options.stringify in persisting theme stores.
26
+ * Existing accepts null (e.g. from getAttribute, getItem); entry accepts null for remove/clear.
27
+ */
28
+ export type StringifyStoredTheme<Themes extends ThemeMap> = (
29
+ themes: Themes,
30
+ existing: string | null | undefined,
31
+ entry: ThemeEntry<Themes> | null | undefined
32
+ ) => string
@@ -1,6 +1,13 @@
1
+ /**
2
+ * Polymorphic theme value: string, array, or object with themeValue.
3
+ * The object form allows storing extra user metadata in persistent stores (localStorage, etc.).
4
+ */
5
+ export type ThemeMapValue = string | readonly string[] | { themeValue: string | readonly string[] }
6
+
1
7
  /**
2
8
  * Record mapping theme keys to their values.
3
- * Each value can be a single string or readonly string[] (e.g. multiple CSS classes).
9
+ * Each value can be a single string, readonly string[] (e.g. multiple CSS classes),
10
+ * or { themeValue: string | string[] } for polymorphic values with extra metadata.
4
11
  * Used by all ThemeStore factories via the themes option.
5
12
  */
6
- export type ThemeMap<Theme extends string = string> = Record<Theme, string | readonly string[]>
13
+ export type ThemeMap<Theme extends string = string> = Record<Theme, ThemeMapValue>
@@ -18,7 +18,5 @@ export interface AsyncThemeStore<Themes extends ThemeMap = ThemeMap> {
18
18
  | (() => ThemeEntry<Themes> | undefined | Promise<ThemeEntry<Themes> | undefined>)
19
19
  | undefined
20
20
  write?: ((entry: ThemeEntry<Themes> | undefined) => void | Promise<void>) | undefined
21
- subscribe?:
22
- | ((handler: (entry: ThemeEntry<Themes> | undefined | null) => void) => () => void)
23
- | undefined
21
+ subscribe?: ((handler: (entry: ThemeEntry<Themes> | undefined) => void) => () => void) | undefined
24
22
  }
@@ -1,9 +1,11 @@
1
1
  import type { Required } from 'type-plus'
2
- import { observeAttributes } from '../../../attributes/observe-attribute.ts'
3
2
  import { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'
4
- import { applyThemeToClassName } from '../../class-name/apply-theme-to-class-name.ts'
5
- import { resolveThemeFromClassName } from '../../class-name/resolve-theme-from-class-name.ts'
6
- import { themeEntry } from '../../theme-entry.ts'
3
+ import { parseClassName } from '../../class-name/parse-class-name.ts'
4
+ import { readClassName } from '../../class-name/read-class-name.ts'
5
+ import { stringifyClassName } from '../../class-name/stringify-class-name.ts'
6
+ import { subscribeClassName } from '../../class-name/subscribe-class-name.ts'
7
+ import { writeClassName } from '../../class-name/write-class-name.ts'
8
+ import type { ParseStoredTheme, StringifyStoredTheme } from '../../theme-entry.types.ts'
7
9
  import type { ThemeMap } from '../../theme-map.types.ts'
8
10
  import type { ThemeStore } from '../theme-store.types.ts'
9
11
 
@@ -11,7 +13,9 @@ import type { ThemeStore } from '../theme-store.types.ts'
11
13
  * Creates a theme store that reads and writes via element class names.
12
14
  *
13
15
  * @param themes - Record mapping theme keys to class name(s)
14
- * @param options.element - Element to operate on (defaults to document.documentElement)
16
+ * @param options.element - Element to operate on (accepts null e.g. from refs). Defaults to document.documentElement.
17
+ * @param options.parse - Custom parser (default: parseClassName)
18
+ * @param options.stringify - Custom serializer (default: stringifyClassName)
15
19
  * @returns ThemeStore
16
20
  *
17
21
  * @example
@@ -25,38 +29,28 @@ import type { ThemeStore } from '../theme-store.types.ts'
25
29
  */
26
30
  export function classNameThemeStore<Themes extends ThemeMap>(
27
31
  themes: Themes,
28
- options?: { element?: Element | undefined }
32
+ options?: {
33
+ element?: Element | null | undefined
34
+ parse?: ParseStoredTheme<Themes> | undefined
35
+ stringify?: StringifyStoredTheme<Themes> | undefined
36
+ }
29
37
  ): Required<ThemeStore<Themes>> {
30
38
  const element = options?.element ?? document?.documentElement
31
39
 
32
40
  if (!element) return dummyThemeStore
33
41
 
42
+ const parse = options?.parse ?? parseClassName
43
+ const stringify = options?.stringify ?? stringifyClassName
44
+
34
45
  return {
35
46
  read() {
36
- const theme = resolveThemeFromClassName(themes, element.className)
37
- if (theme === undefined) return undefined
38
- return themeEntry(themes, theme)
47
+ return readClassName(themes, { element, parse })
39
48
  },
40
49
  write(entry) {
41
- applyThemeToClassName(themes, element, entry)
50
+ writeClassName(themes, entry, { element, stringify })
42
51
  },
43
52
  subscribe(handler) {
44
- let lastEmitted: keyof Themes | undefined | null = null
45
- const observer = observeAttributes(
46
- {
47
- class: (value) => {
48
- const theme = value ? resolveThemeFromClassName(themes, value) : undefined
49
- const entry = theme ? themeEntry(themes, theme) : undefined
50
- const key = theme ?? undefined
51
-
52
- if (lastEmitted === key) return
53
- lastEmitted = key
54
- handler(entry)
55
- }
56
- },
57
- element
58
- )
59
- return () => observer.disconnect()
53
+ return subscribeClassName(themes, handler, { element, parse })
60
54
  }
61
55
  }
62
56
  }
@@ -1,48 +1,20 @@
1
1
  import type { Required } from 'type-plus'
2
2
  import { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'
3
3
  import { parseStoredTheme } from '../../_utils/parse-stored-theme.ts'
4
- import { themeEntry } from '../../theme-entry.ts'
5
- import type { ThemeEntry } from '../../theme-entry.types.ts'
4
+ import { getCookieFromHeader } from '../../cookie/_cookie-utils.ts'
5
+ import { readCookieTheme } from '../../cookie/read-cookie-theme.ts'
6
+ import { writeCookieTheme } from '../../cookie/write-cookie-theme.ts'
7
+ import type { ParseStoredTheme, ThemeEntry } from '../../theme-entry.types.ts'
6
8
  import type { ThemeMap } from '../../theme-map.types.ts'
7
9
  import type { ThemeStore } from '../theme-store.types.ts'
8
10
 
9
- export interface CookieThemeStoreOptions {
11
+ export interface CookieThemeStoreOptions<Themes extends ThemeMap = ThemeMap> {
10
12
  cookieName: string
11
13
  path?: string | undefined
12
14
  maxAge?: number | undefined
13
15
  sameSite?: 'lax' | 'strict' | 'none' | undefined
14
16
  secure?: boolean | undefined
15
- }
16
-
17
- function getCookieValue(name: string): string | null {
18
- if (typeof document === 'undefined' || !document.cookie) return null
19
- const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))
20
- const value = match?.[1]
21
- return value !== undefined ? decodeURIComponent(value) : null
22
- }
23
-
24
- function setCookie(
25
- name: string,
26
- value: string,
27
- options: {
28
- path?: string | undefined
29
- maxAge?: number | undefined
30
- sameSite?: 'lax' | 'strict' | 'none' | undefined
31
- secure?: boolean | undefined
32
- }
33
- ) {
34
- const parts = [`${name}=${encodeURIComponent(value)}`]
35
- parts.push(`path=${options.path ?? '/'}`)
36
- if (options.maxAge !== undefined) parts.push(`max-age=${options.maxAge}`)
37
- if (options.sameSite !== undefined) parts.push(`samesite=${options.sameSite}`)
38
- if (options.secure) parts.push('secure')
39
- // biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API has limited support; document.cookie is standard for theme persistence
40
- document.cookie = parts.join('; ')
41
- }
42
-
43
- function deleteCookie(name: string, path = '/') {
44
- // biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API has limited support; document.cookie is standard for theme persistence
45
- document.cookie = `${name}=; path=${path}; max-age=0`
17
+ parse?: ParseStoredTheme<Themes> | undefined
46
18
  }
47
19
 
48
20
  /**
@@ -58,6 +30,7 @@ function deleteCookie(name: string, path = '/') {
58
30
  * @param options.maxAge - Cookie max-age in seconds
59
31
  * @param options.sameSite - Cookie sameSite attribute
60
32
  * @param options.secure - Cookie secure attribute
33
+ * @param options.parse - Optional custom parser for stored string (default: parseStoredTheme)
61
34
  * @returns ThemeStore
62
35
  *
63
36
  * @example
@@ -71,9 +44,9 @@ function deleteCookie(name: string, path = '/') {
71
44
  */
72
45
  export function cookieThemeStore<Themes extends ThemeMap>(
73
46
  themes: Themes,
74
- options: CookieThemeStoreOptions
47
+ options: CookieThemeStoreOptions<Themes>
75
48
  ): Required<ThemeStore<Themes>> {
76
- const { cookieName, path = '/', maxAge, sameSite, secure } = options
49
+ const { cookieName, path = '/', maxAge, sameSite, secure, parse = parseStoredTheme } = options
77
50
 
78
51
  if (document.cookie === undefined) {
79
52
  return dummyThemeStore
@@ -83,10 +56,7 @@ export function cookieThemeStore<Themes extends ThemeMap>(
83
56
  let lastNotifiedKey: keyof Themes | undefined = read()?.theme ?? undefined
84
57
 
85
58
  function read() {
86
- const stored = getCookieValue(cookieName)
87
- const theme = parseStoredTheme(themes, stored)
88
- if (theme === undefined) return undefined
89
- return themeEntry(themes, theme)
59
+ return readCookieTheme(themes, { cookieName, path, parse })
90
60
  }
91
61
 
92
62
  function notify() {
@@ -101,20 +71,13 @@ export function cookieThemeStore<Themes extends ThemeMap>(
101
71
  read,
102
72
  write(entry) {
103
73
  try {
104
- if (entry === undefined) {
105
- deleteCookie(cookieName, path)
106
- } else {
107
- const opts: {
108
- path: string
109
- maxAge?: number
110
- sameSite?: 'lax' | 'strict' | 'none'
111
- secure?: boolean
112
- } = { path }
113
- if (maxAge !== undefined) opts.maxAge = maxAge
114
- if (sameSite !== undefined) opts.sameSite = sameSite
115
- if (secure) opts.secure = true
116
- setCookie(cookieName, JSON.stringify(entry), opts)
117
- }
74
+ writeCookieTheme(themes, entry, {
75
+ cookieName,
76
+ path,
77
+ maxAge,
78
+ sameSite,
79
+ secure
80
+ })
118
81
  notify()
119
82
  } catch {
120
83
  // Ignore quota or other errors
@@ -129,12 +92,6 @@ export function cookieThemeStore<Themes extends ThemeMap>(
129
92
  } satisfies ThemeStore<Themes>
130
93
  }
131
94
 
132
- function getCookieFromHeader(cookieHeader: string, name: string): string | null {
133
- const match = cookieHeader.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))
134
- const value = match?.[1]
135
- return value !== undefined ? decodeURIComponent(value.trim()) : null
136
- }
137
-
138
95
  /**
139
96
  * Reads the theme from cookies during SSR. Use with the request's Cookie header or
140
97
  * a framework's cookie API (e.g. Next.js cookies()).
@@ -168,7 +125,5 @@ export function getThemeFromCookie<Themes extends ThemeMap>(
168
125
  : cookieSource
169
126
  ? getCookieFromHeader(cookieSource, cookieName)
170
127
  : null
171
- const theme = parseStoredTheme(themes, stored)
172
- if (theme === undefined) return undefined
173
- return themeEntry(themes, theme)
128
+ return parseStoredTheme(themes, stored ?? undefined)
174
129
  }
@@ -1,60 +1,73 @@
1
- import type { Required } from 'type-plus'
2
- import { getDataAttribute } from '../../../attributes/get-data-attribute.ts'
3
- import { observeDataAttributes } from '../../../attributes/observe-data-attribute.ts'
4
- import { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'
5
- import { applyThemeToDataAttribute } from '../../data-attribute/apply-theme-to-data-attribute.ts'
6
- import { resolveThemeFromDataAttribute } from '../../data-attribute/resolve-theme-from-data-attribute.ts'
7
- import { themeEntry } from '../../theme-entry.ts'
1
+ import { SEPARATOR_SPACE } from '../../data-attribute/_constant.ts'
2
+ import { parseDataAttribute } from '../../data-attribute/parse-data-attribute.ts'
3
+ import { readDataAttribute } from '../../data-attribute/read-data-attribute.ts'
4
+ import { stringifyDataAttribute } from '../../data-attribute/stringify-data-attribute.ts'
5
+ import { subscribeDataAttribute } from '../../data-attribute/subscribe-data-attribute.ts'
6
+ import { writeDataAttribute } from '../../data-attribute/write-data-attribute.ts'
7
+ import type { ParseStoredTheme, StringifyStoredTheme } from '../../theme-entry.types.ts'
8
8
  import type { ThemeMap } from '../../theme-map.types.ts'
9
9
  import type { ThemeStore } from '../theme-store.types.ts'
10
10
 
11
11
  /**
12
12
  * Creates a theme store that reads and writes via a data attribute.
13
13
  *
14
+ * read: parse(themes, getDataAttribute(element, attribute)) → ThemeEntry
15
+ * write: setAttribute(attribute, stringify(themes, getDataAttribute(element, attribute), entry))
16
+ *
17
+ * Supports space-separated attribute values by default. Use `parse` and `stringify` to customize
18
+ * (e.g. comma-separated via curried parseDataAttribute/stringifyDataAttribute).
19
+ *
14
20
  * @param themes - Record mapping theme keys to attribute values
15
21
  * @param options.attributeName - Data attribute name (e.g. `data-theme`)
16
- * @param options.element - Element to operate on (defaults to document.documentElement)
22
+ * @param options.element - Element to operate on (accepts null e.g. from refs). Defaults to document.documentElement.
23
+ * @param options.parse - Custom parser (default: parseDataAttribute with space separator)
24
+ * @param options.stringify - Custom serializer (default: stringifyDataAttribute with space separator)
17
25
  * @returns ThemeStore
18
26
  *
19
27
  * @example
20
28
  * ```ts
21
29
  * const themes = { current: 'current', grayscale: 'grayscale' }
22
30
  * const store = dataAttributeThemeStore(themes, { attributeName: 'data-theme' })
23
- * store.read() // returns themeResult from data attribute
31
+ * store.read() // returns ThemeEntry from data attribute
24
32
  * store.write(themeEntry(themes, 'grayscale'))
25
- * store.subscribe((themeResult) => {})
33
+ * store.subscribe((entry) => {})
34
+ * ```
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * // Comma-separated
39
+ * const store = dataAttributeThemeStore(themes, {
40
+ * attributeName: 'data-theme',
41
+ * parse: (t, v) => parseDataAttribute(t, v, { separator: ',' }),
42
+ * stringify: (t, x, e) => stringifyDataAttribute(t, x, e, { separator: ',' })
43
+ * })
26
44
  * ```
27
45
  */
28
46
  export function dataAttributeThemeStore<Themes extends ThemeMap>(
29
47
  themes: Themes,
30
- options: { attributeName: `data-${string}`; element?: Element | undefined }
48
+ options: {
49
+ attributeName: `data-${string}`
50
+ element?: Element | null | undefined
51
+ parse?: ParseStoredTheme<Themes> | undefined
52
+ stringify?: StringifyStoredTheme<Themes> | undefined
53
+ }
31
54
  ) {
32
55
  const element = options.element ?? document?.documentElement
33
- const { attributeName } = options
34
-
35
- if (!element) return dummyThemeStore as Required<ThemeStore<Themes>>
56
+ const {
57
+ attributeName,
58
+ parse = (t, v) => parseDataAttribute(t, v, { separator: SEPARATOR_SPACE }),
59
+ stringify = (t, x, e) => stringifyDataAttribute(t, x, e, { separator: SEPARATOR_SPACE })
60
+ } = options
36
61
 
37
62
  return {
38
63
  read() {
39
- const value = getDataAttribute(attributeName, element)
40
- const theme = resolveThemeFromDataAttribute(themes, value)
41
- if (theme === undefined) return undefined
42
- return themeEntry(themes, theme)
64
+ return readDataAttribute(themes, attributeName, { element, parse })
43
65
  },
44
66
  write(entry) {
45
- applyThemeToDataAttribute(element, attributeName, entry)
67
+ writeDataAttribute(themes, attributeName, entry, { element, stringify })
46
68
  },
47
69
  subscribe(handler) {
48
- const observer = observeDataAttributes<string, `data-${string}`>(
49
- {
50
- [attributeName]: (value) => {
51
- const theme = value ? resolveThemeFromDataAttribute(themes, value) : undefined
52
- handler(theme ? themeEntry(themes, theme) : undefined)
53
- }
54
- },
55
- element
56
- )
57
- return () => observer.disconnect()
70
+ return subscribeDataAttribute(themes, attributeName, handler, { element, parse })
58
71
  }
59
72
  } satisfies ThemeStore<Themes>
60
73
  }
@@ -33,7 +33,7 @@ export function inMemoryThemeStore<Themes extends ThemeMap>(themes: Themes) {
33
33
  return {
34
34
  read,
35
35
  write(entry) {
36
- if (entry === undefined) {
36
+ if (entry == null) {
37
37
  if (value === undefined || value === null) return
38
38
  value = undefined
39
39
  for (const fn of listeners) fn(undefined)
@@ -1,7 +1,7 @@
1
1
  import { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'
2
- import { parseStoredTheme } from '../../_utils/parse-stored-theme.ts'
3
- import { themeEntry } from '../../theme-entry.ts'
4
- import type { ThemeEntry } from '../../theme-entry.types.ts'
2
+ import { readLocalStorage } from '../../local-storage/read-local-storage.ts'
3
+ import { writeLocalStorage } from '../../local-storage/write-local-storage.ts'
4
+ import type { ParseStoredTheme, StringifyStoredTheme, ThemeEntry } from '../../theme-entry.types.ts'
5
5
  import type { ThemeMap } from '../../theme-map.types.ts'
6
6
  import type { ThemeStore } from '../theme-store.types.ts'
7
7
 
@@ -13,6 +13,9 @@ import type { ThemeStore } from '../theme-store.types.ts'
13
13
  *
14
14
  * @param themes - Record mapping theme keys to values (for validation)
15
15
  * @param options.storageKey - localStorage key
16
+ * @param options.parse - Optional custom parser for stored string (default: parseStoredTheme)
17
+ * @param options.stringify - Optional custom serializer (default: JSON.stringify)
18
+ * @param options.onError - Optional callback invoked when storage write throws
16
19
  * @returns ThemeStore
17
20
  *
18
21
  * @example
@@ -26,11 +29,16 @@ import type { ThemeStore } from '../theme-store.types.ts'
26
29
  */
27
30
  export function localStorageThemeStore<Themes extends ThemeMap>(
28
31
  themes: Themes,
29
- options: { storageKey: string }
32
+ options: {
33
+ storageKey: string
34
+ parse?: ParseStoredTheme<Themes> | undefined
35
+ stringify?: StringifyStoredTheme<Themes> | undefined
36
+ onError?: ((error: unknown) => void) | undefined
37
+ }
30
38
  ) {
31
- const { storageKey } = options
39
+ const { storageKey, parse, stringify, onError } = options
32
40
 
33
- if (typeof window === 'undefined' || !window.localStorage) {
41
+ if (!window?.localStorage) {
34
42
  return dummyThemeStore satisfies ThemeStore<Themes>
35
43
  }
36
44
 
@@ -38,10 +46,7 @@ export function localStorageThemeStore<Themes extends ThemeMap>(
38
46
  let lastNotifiedKey: keyof Themes | undefined = read()?.theme ?? undefined
39
47
 
40
48
  function read() {
41
- const stored = window.localStorage.getItem(storageKey)
42
- const theme = parseStoredTheme(themes, stored)
43
- if (theme === undefined) return undefined
44
- return themeEntry(themes, theme)
49
+ return readLocalStorage(themes, storageKey, { parse })
45
50
  }
46
51
 
47
52
  function notify() {
@@ -55,16 +60,8 @@ export function localStorageThemeStore<Themes extends ThemeMap>(
55
60
  return {
56
61
  read,
57
62
  write(entry) {
58
- try {
59
- if (entry === undefined) {
60
- window.localStorage.removeItem(storageKey)
61
- } else {
62
- window.localStorage.setItem(storageKey, JSON.stringify(entry))
63
- }
64
- notify()
65
- } catch {
66
- // Ignore quota or other errors
67
- }
63
+ writeLocalStorage(themes, storageKey, entry, { stringify, onError })
64
+ notify()
68
65
  },
69
66
  subscribe(handler) {
70
67
  handlers.add(handler)
@@ -1,7 +1,6 @@
1
1
  import type { RequiredPick } from 'type-plus'
2
- import { getPrefersColorScheme } from '../../../color-scheme/get-prefers-color-scheme.ts'
3
- import { observePrefersColorScheme } from '../../../color-scheme/observe-prefers-color-scheme.ts'
4
- import { themeEntry } from '../../theme-entry.ts'
2
+ import { readPrefersColorSchemeTheme } from '../../prefers-color-scheme-theme/read-prefers-color-scheme-theme.ts'
3
+ import { subscribePrefersColorSchemeTheme } from '../../prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.ts'
5
4
  import type { ThemeStore } from '../theme-store.types.ts'
6
5
 
7
6
  type PrefersColorSchemeThemes = {
@@ -34,10 +33,10 @@ export function prefersColorSchemeThemeStore<Themes extends PrefersColorSchemeTh
34
33
  ): RequiredPick<ThemeStore<Themes>, 'read' | 'subscribe'> {
35
34
  return {
36
35
  read() {
37
- return themeEntry(themes, getPrefersColorScheme())
36
+ return readPrefersColorSchemeTheme(themes)
38
37
  },
39
38
  subscribe(handler) {
40
- return observePrefersColorScheme((scheme) => handler(themeEntry(themes, scheme)))
39
+ return subscribePrefersColorSchemeTheme(themes, handler)
41
40
  }
42
41
  }
43
42
  }