@just-web/toolkits 1.0.0 → 2.0.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 (315) hide show
  1. package/dist/react/hooks/use-theme-by-class-name.cjs +1 -5
  2. package/dist/react/hooks/use-theme-by-class-name.cjs.map +1 -1
  3. package/dist/react/hooks/use-theme-by-class-name.d.cts.map +1 -1
  4. package/dist/react/hooks/use-theme-by-class-name.d.mts.map +1 -1
  5. package/dist/react/hooks/use-theme-by-class-name.mjs +1 -5
  6. package/dist/react/hooks/use-theme-by-class-name.mjs.map +1 -1
  7. package/dist/react/hooks/use-theme-by-data-attribute.cjs +1 -6
  8. package/dist/react/hooks/use-theme-by-data-attribute.cjs.map +1 -1
  9. package/dist/react/hooks/use-theme-by-data-attribute.d.cts.map +1 -1
  10. package/dist/react/hooks/use-theme-by-data-attribute.d.mts.map +1 -1
  11. package/dist/react/hooks/use-theme-by-data-attribute.mjs +1 -6
  12. package/dist/react/hooks/use-theme-by-data-attribute.mjs.map +1 -1
  13. package/dist/react/hooks/use-theme-by-local-storage.cjs +1 -5
  14. package/dist/react/hooks/use-theme-by-local-storage.cjs.map +1 -1
  15. package/dist/react/hooks/use-theme-by-local-storage.d.cts.map +1 -1
  16. package/dist/react/hooks/use-theme-by-local-storage.d.mts.map +1 -1
  17. package/dist/react/hooks/use-theme-by-local-storage.mjs +1 -5
  18. package/dist/react/hooks/use-theme-by-local-storage.mjs.map +1 -1
  19. package/dist/theme/_utils/match-attribute-value-to-theme.cjs +29 -0
  20. package/dist/theme/_utils/match-attribute-value-to-theme.cjs.map +1 -0
  21. package/dist/theme/_utils/match-attribute-value-to-theme.mjs +28 -0
  22. package/dist/theme/_utils/match-attribute-value-to-theme.mjs.map +1 -0
  23. package/dist/theme/_utils/parse-stored-theme.cjs +61 -7
  24. package/dist/theme/_utils/parse-stored-theme.cjs.map +1 -1
  25. package/dist/theme/_utils/parse-stored-theme.mjs +61 -7
  26. package/dist/theme/_utils/parse-stored-theme.mjs.map +1 -1
  27. package/dist/theme/_utils/resolve-theme-map-value.cjs +19 -0
  28. package/dist/theme/_utils/resolve-theme-map-value.cjs.map +1 -0
  29. package/dist/theme/_utils/resolve-theme-map-value.mjs +17 -0
  30. package/dist/theme/_utils/resolve-theme-map-value.mjs.map +1 -0
  31. package/dist/theme/class-name/parse-class-name.cjs +32 -0
  32. package/dist/theme/class-name/parse-class-name.cjs.map +1 -0
  33. package/dist/theme/class-name/parse-class-name.d.cts +20 -0
  34. package/dist/theme/class-name/parse-class-name.d.cts.map +1 -0
  35. package/dist/theme/class-name/parse-class-name.d.mts +20 -0
  36. package/dist/theme/class-name/parse-class-name.d.mts.map +1 -0
  37. package/dist/theme/class-name/parse-class-name.mjs +31 -0
  38. package/dist/theme/class-name/parse-class-name.mjs.map +1 -0
  39. package/dist/theme/class-name/read-class-name.cjs +20 -0
  40. package/dist/theme/class-name/read-class-name.cjs.map +1 -0
  41. package/dist/theme/class-name/read-class-name.d.cts +20 -0
  42. package/dist/theme/class-name/read-class-name.d.cts.map +1 -0
  43. package/dist/theme/class-name/read-class-name.d.mts +20 -0
  44. package/dist/theme/class-name/read-class-name.d.mts.map +1 -0
  45. package/dist/theme/class-name/read-class-name.mjs +20 -0
  46. package/dist/theme/class-name/read-class-name.mjs.map +1 -0
  47. package/dist/theme/class-name/stringify-class-name.cjs +31 -0
  48. package/dist/theme/class-name/stringify-class-name.cjs.map +1 -0
  49. package/dist/theme/class-name/stringify-class-name.d.cts +21 -0
  50. package/dist/theme/class-name/stringify-class-name.d.cts.map +1 -0
  51. package/dist/theme/class-name/stringify-class-name.d.mts +21 -0
  52. package/dist/theme/class-name/stringify-class-name.d.mts.map +1 -0
  53. package/dist/theme/class-name/stringify-class-name.mjs +31 -0
  54. package/dist/theme/class-name/stringify-class-name.mjs.map +1 -0
  55. package/dist/theme/class-name/subscribe-class-name.cjs +31 -0
  56. package/dist/theme/class-name/subscribe-class-name.cjs.map +1 -0
  57. package/dist/theme/class-name/subscribe-class-name.d.cts +21 -0
  58. package/dist/theme/class-name/subscribe-class-name.d.cts.map +1 -0
  59. package/dist/theme/class-name/subscribe-class-name.d.mts +21 -0
  60. package/dist/theme/class-name/subscribe-class-name.d.mts.map +1 -0
  61. package/dist/theme/class-name/subscribe-class-name.mjs +31 -0
  62. package/dist/theme/class-name/subscribe-class-name.mjs.map +1 -0
  63. package/dist/theme/class-name/write-class-name.cjs +20 -0
  64. package/dist/theme/class-name/write-class-name.cjs.map +1 -0
  65. package/dist/theme/class-name/write-class-name.d.cts +20 -0
  66. package/dist/theme/class-name/write-class-name.d.cts.map +1 -0
  67. package/dist/theme/class-name/write-class-name.d.mts +20 -0
  68. package/dist/theme/class-name/write-class-name.d.mts.map +1 -0
  69. package/dist/theme/class-name/write-class-name.mjs +20 -0
  70. package/dist/theme/class-name/write-class-name.mjs.map +1 -0
  71. package/dist/theme/cookie/_cookie-utils.cjs +37 -0
  72. package/dist/theme/cookie/_cookie-utils.cjs.map +1 -0
  73. package/dist/theme/cookie/_cookie-utils.mjs +33 -0
  74. package/dist/theme/cookie/_cookie-utils.mjs.map +1 -0
  75. package/dist/theme/cookie/read-cookie-theme.cjs +22 -0
  76. package/dist/theme/cookie/read-cookie-theme.cjs.map +1 -0
  77. package/dist/theme/cookie/read-cookie-theme.d.cts +22 -0
  78. package/dist/theme/cookie/read-cookie-theme.d.cts.map +1 -0
  79. package/dist/theme/cookie/read-cookie-theme.d.mts +22 -0
  80. package/dist/theme/cookie/read-cookie-theme.d.mts.map +1 -0
  81. package/dist/theme/cookie/read-cookie-theme.mjs +22 -0
  82. package/dist/theme/cookie/read-cookie-theme.mjs.map +1 -0
  83. package/dist/theme/cookie/write-cookie-theme.cjs +29 -0
  84. package/dist/theme/cookie/write-cookie-theme.cjs.map +1 -0
  85. package/dist/theme/cookie/write-cookie-theme.d.cts +24 -0
  86. package/dist/theme/cookie/write-cookie-theme.d.cts.map +1 -0
  87. package/dist/theme/cookie/write-cookie-theme.d.mts +24 -0
  88. package/dist/theme/cookie/write-cookie-theme.d.mts.map +1 -0
  89. package/dist/theme/cookie/write-cookie-theme.mjs +29 -0
  90. package/dist/theme/cookie/write-cookie-theme.mjs.map +1 -0
  91. package/dist/theme/data-attribute/_constant.cjs +7 -0
  92. package/dist/theme/data-attribute/_constant.cjs.map +1 -0
  93. package/dist/theme/data-attribute/_constant.mjs +6 -0
  94. package/dist/theme/data-attribute/_constant.mjs.map +1 -0
  95. package/dist/theme/data-attribute/parse-data-attribute.cjs +24 -0
  96. package/dist/theme/data-attribute/parse-data-attribute.cjs.map +1 -0
  97. package/dist/theme/data-attribute/parse-data-attribute.d.cts +21 -0
  98. package/dist/theme/data-attribute/parse-data-attribute.d.cts.map +1 -0
  99. package/dist/theme/data-attribute/parse-data-attribute.d.mts +21 -0
  100. package/dist/theme/data-attribute/parse-data-attribute.d.mts.map +1 -0
  101. package/dist/theme/data-attribute/parse-data-attribute.mjs +24 -0
  102. package/dist/theme/data-attribute/parse-data-attribute.mjs.map +1 -0
  103. package/dist/theme/data-attribute/read-data-attribute.cjs +23 -0
  104. package/dist/theme/data-attribute/read-data-attribute.cjs.map +1 -0
  105. package/dist/theme/data-attribute/read-data-attribute.d.cts +21 -0
  106. package/dist/theme/data-attribute/read-data-attribute.d.cts.map +1 -0
  107. package/dist/theme/data-attribute/read-data-attribute.d.mts +21 -0
  108. package/dist/theme/data-attribute/read-data-attribute.d.mts.map +1 -0
  109. package/dist/theme/data-attribute/read-data-attribute.mjs +23 -0
  110. package/dist/theme/data-attribute/read-data-attribute.mjs.map +1 -0
  111. package/dist/theme/data-attribute/stringify-data-attribute.cjs +33 -0
  112. package/dist/theme/data-attribute/stringify-data-attribute.cjs.map +1 -0
  113. package/dist/theme/data-attribute/stringify-data-attribute.d.cts +23 -0
  114. package/dist/theme/data-attribute/stringify-data-attribute.d.cts.map +1 -0
  115. package/dist/theme/data-attribute/stringify-data-attribute.d.mts +23 -0
  116. package/dist/theme/data-attribute/stringify-data-attribute.d.mts.map +1 -0
  117. package/dist/theme/data-attribute/stringify-data-attribute.mjs +33 -0
  118. package/dist/theme/data-attribute/stringify-data-attribute.mjs.map +1 -0
  119. package/dist/theme/data-attribute/subscribe-data-attribute.cjs +28 -0
  120. package/dist/theme/data-attribute/subscribe-data-attribute.cjs.map +1 -0
  121. package/dist/theme/data-attribute/subscribe-data-attribute.d.cts +22 -0
  122. package/dist/theme/data-attribute/subscribe-data-attribute.d.cts.map +1 -0
  123. package/dist/theme/data-attribute/subscribe-data-attribute.d.mts +22 -0
  124. package/dist/theme/data-attribute/subscribe-data-attribute.d.mts.map +1 -0
  125. package/dist/theme/data-attribute/subscribe-data-attribute.mjs +28 -0
  126. package/dist/theme/data-attribute/subscribe-data-attribute.mjs.map +1 -0
  127. package/dist/theme/data-attribute/write-data-attribute.cjs +30 -0
  128. package/dist/theme/data-attribute/write-data-attribute.cjs.map +1 -0
  129. package/dist/theme/data-attribute/write-data-attribute.d.cts +21 -0
  130. package/dist/theme/data-attribute/write-data-attribute.d.cts.map +1 -0
  131. package/dist/theme/data-attribute/write-data-attribute.d.mts +21 -0
  132. package/dist/theme/data-attribute/write-data-attribute.d.mts.map +1 -0
  133. package/dist/theme/data-attribute/write-data-attribute.mjs +30 -0
  134. package/dist/theme/data-attribute/write-data-attribute.mjs.map +1 -0
  135. package/dist/theme/local-storage/read-local-storage.cjs +22 -0
  136. package/dist/theme/local-storage/read-local-storage.cjs.map +1 -0
  137. package/dist/theme/local-storage/read-local-storage.d.cts +19 -0
  138. package/dist/theme/local-storage/read-local-storage.d.cts.map +1 -0
  139. package/dist/theme/local-storage/read-local-storage.d.mts +19 -0
  140. package/dist/theme/local-storage/read-local-storage.d.mts.map +1 -0
  141. package/dist/theme/local-storage/read-local-storage.mjs +22 -0
  142. package/dist/theme/local-storage/read-local-storage.mjs.map +1 -0
  143. package/dist/theme/local-storage/write-local-storage.cjs +26 -0
  144. package/dist/theme/local-storage/write-local-storage.cjs.map +1 -0
  145. package/dist/theme/local-storage/write-local-storage.d.cts +23 -0
  146. package/dist/theme/local-storage/write-local-storage.d.cts.map +1 -0
  147. package/dist/theme/local-storage/write-local-storage.d.mts +23 -0
  148. package/dist/theme/local-storage/write-local-storage.d.mts.map +1 -0
  149. package/dist/theme/local-storage/write-local-storage.mjs +26 -0
  150. package/dist/theme/local-storage/write-local-storage.mjs.map +1 -0
  151. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.cjs +20 -0
  152. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.cjs.map +1 -0
  153. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.d.cts +23 -0
  154. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.d.cts.map +1 -0
  155. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.d.mts +23 -0
  156. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.d.mts.map +1 -0
  157. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.mjs +20 -0
  158. package/dist/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.mjs.map +1 -0
  159. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.cjs +20 -0
  160. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.cjs.map +1 -0
  161. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.d.cts +20 -0
  162. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.d.cts.map +1 -0
  163. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.d.mts +20 -0
  164. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.d.mts.map +1 -0
  165. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.mjs +20 -0
  166. package/dist/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.mjs.map +1 -0
  167. package/dist/theme/session-storage/read-session-storage.cjs +22 -0
  168. package/dist/theme/session-storage/read-session-storage.cjs.map +1 -0
  169. package/dist/theme/session-storage/read-session-storage.d.cts +19 -0
  170. package/dist/theme/session-storage/read-session-storage.d.cts.map +1 -0
  171. package/dist/theme/session-storage/read-session-storage.d.mts +19 -0
  172. package/dist/theme/session-storage/read-session-storage.d.mts.map +1 -0
  173. package/dist/theme/session-storage/read-session-storage.mjs +22 -0
  174. package/dist/theme/session-storage/read-session-storage.mjs.map +1 -0
  175. package/dist/theme/session-storage/write-session-storage.cjs +26 -0
  176. package/dist/theme/session-storage/write-session-storage.cjs.map +1 -0
  177. package/dist/theme/session-storage/write-session-storage.d.cts +23 -0
  178. package/dist/theme/session-storage/write-session-storage.d.cts.map +1 -0
  179. package/dist/theme/session-storage/write-session-storage.d.mts +23 -0
  180. package/dist/theme/session-storage/write-session-storage.d.mts.map +1 -0
  181. package/dist/theme/session-storage/write-session-storage.mjs +26 -0
  182. package/dist/theme/session-storage/write-session-storage.mjs.map +1 -0
  183. package/dist/theme/theme-entry.types.d.cts +11 -1
  184. package/dist/theme/theme-entry.types.d.cts.map +1 -1
  185. package/dist/theme/theme-entry.types.d.mts +11 -1
  186. package/dist/theme/theme-entry.types.d.mts.map +1 -1
  187. package/dist/theme/theme-map.types.d.cts +11 -3
  188. package/dist/theme/theme-map.types.d.cts.map +1 -1
  189. package/dist/theme/theme-map.types.d.mts +11 -3
  190. package/dist/theme/theme-map.types.d.mts.map +1 -1
  191. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs +21 -18
  192. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs.map +1 -1
  193. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.cts +5 -0
  194. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.cts.map +1 -1
  195. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.mts +5 -0
  196. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.mts.map +1 -1
  197. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs +21 -18
  198. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs.map +1 -1
  199. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.cjs +18 -36
  200. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.cjs.map +1 -1
  201. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.cts +5 -3
  202. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.cts.map +1 -1
  203. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.mts +5 -3
  204. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.mts.map +1 -1
  205. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.mjs +18 -36
  206. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.mjs.map +1 -1
  207. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs +39 -19
  208. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs.map +1 -1
  209. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.cts +28 -5
  210. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.cts.map +1 -1
  211. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.mts +28 -5
  212. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.mts.map +1 -1
  213. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs +39 -19
  214. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs.map +1 -1
  215. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.cjs +13 -12
  216. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.cjs.map +1 -1
  217. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.cts +7 -1
  218. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.cts.map +1 -1
  219. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.mts +7 -1
  220. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.mts.map +1 -1
  221. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs +13 -12
  222. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs.map +1 -1
  223. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.cjs +4 -5
  224. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.cjs.map +1 -1
  225. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.cts.map +1 -1
  226. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.mts.map +1 -1
  227. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs +4 -5
  228. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs.map +1 -1
  229. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.cjs +13 -12
  230. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.cjs.map +1 -1
  231. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.cts +7 -1
  232. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.cts.map +1 -1
  233. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.mts +7 -1
  234. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.mts.map +1 -1
  235. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs +13 -12
  236. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs.map +1 -1
  237. package/dist/theme/web-storage/read-web-storage.cjs +20 -0
  238. package/dist/theme/web-storage/read-web-storage.cjs.map +1 -0
  239. package/dist/theme/web-storage/read-web-storage.d.cts +21 -0
  240. package/dist/theme/web-storage/read-web-storage.d.cts.map +1 -0
  241. package/dist/theme/web-storage/read-web-storage.d.mts +21 -0
  242. package/dist/theme/web-storage/read-web-storage.d.mts.map +1 -0
  243. package/dist/theme/web-storage/read-web-storage.mjs +20 -0
  244. package/dist/theme/web-storage/read-web-storage.mjs.map +1 -0
  245. package/dist/theme/web-storage/write-web-storage.cjs +33 -0
  246. package/dist/theme/web-storage/write-web-storage.cjs.map +1 -0
  247. package/dist/theme/web-storage/write-web-storage.d.cts +25 -0
  248. package/dist/theme/web-storage/write-web-storage.d.cts.map +1 -0
  249. package/dist/theme/web-storage/write-web-storage.d.mts +25 -0
  250. package/dist/theme/web-storage/write-web-storage.d.mts.map +1 -0
  251. package/dist/theme/web-storage/write-web-storage.mjs +32 -0
  252. package/dist/theme/web-storage/write-web-storage.mjs.map +1 -0
  253. package/dist/theme.cjs +41 -1
  254. package/dist/theme.d.cts +23 -3
  255. package/dist/theme.d.mts +23 -3
  256. package/dist/theme.mjs +21 -1
  257. package/package.json +1 -1
  258. package/src/react/hooks/use-theme-by-class-name.ts +3 -8
  259. package/src/react/hooks/use-theme-by-data-attribute.ts +3 -10
  260. package/src/react/hooks/use-theme-by-local-storage.ts +3 -9
  261. package/src/testing/theme/theme-result-card.tsx +1 -0
  262. package/src/theme/_utils/match-attribute-value-to-theme.ts +36 -0
  263. package/src/theme/_utils/parse-stored-theme.ts +52 -12
  264. package/src/theme/_utils/resolve-theme-map-value.ts +15 -0
  265. package/src/theme/class-name/parse-class-name.ts +31 -0
  266. package/src/theme/class-name/read-class-name.ts +24 -0
  267. package/src/theme/class-name/stringify-class-name.ts +36 -0
  268. package/src/theme/class-name/subscribe-class-name.ts +39 -0
  269. package/src/theme/class-name/write-class-name.ts +24 -0
  270. package/src/theme/cookie/_cookie-utils.ts +45 -0
  271. package/src/theme/cookie/read-cookie-theme.ts +33 -0
  272. package/src/theme/cookie/write-cookie-theme.ts +48 -0
  273. package/src/theme/data-attribute/_constant.ts +1 -0
  274. package/src/theme/data-attribute/parse-data-attribute.ts +25 -0
  275. package/src/theme/data-attribute/read-data-attribute.ts +29 -0
  276. package/src/theme/data-attribute/stringify-data-attribute.ts +39 -0
  277. package/src/theme/data-attribute/subscribe-data-attribute.ts +39 -0
  278. package/src/theme/data-attribute/write-data-attribute.ts +40 -0
  279. package/src/theme/local-storage/read-local-storage.ts +23 -0
  280. package/src/theme/local-storage/write-local-storage.ts +31 -0
  281. package/src/theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.ts +30 -0
  282. package/src/theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.ts +24 -0
  283. package/src/theme/session-storage/read-session-storage.ts +23 -0
  284. package/src/theme/session-storage/write-session-storage.ts +31 -0
  285. package/src/theme/theme-entry.types.ts +19 -0
  286. package/src/theme/theme-map.types.ts +9 -2
  287. package/src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts +19 -25
  288. package/src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts +18 -63
  289. package/src/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.ts +41 -28
  290. package/src/theme/theme-store/local-storage-theme-store/local-storage-theme-store.ts +17 -20
  291. package/src/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.ts +4 -5
  292. package/src/theme/theme-store/session-storage-theme-store/session-storage-theme-store.ts +17 -20
  293. package/src/theme/web-storage/read-web-storage.ts +22 -0
  294. package/src/theme/web-storage/write-web-storage.ts +46 -0
  295. package/src/theme.ts +20 -0
  296. package/dist/theme/class-name/apply-theme-to-class-name.cjs +0 -23
  297. package/dist/theme/class-name/apply-theme-to-class-name.cjs.map +0 -1
  298. package/dist/theme/class-name/apply-theme-to-class-name.mjs +0 -22
  299. package/dist/theme/class-name/apply-theme-to-class-name.mjs.map +0 -1
  300. package/dist/theme/class-name/resolve-theme-from-class-name.cjs +0 -23
  301. package/dist/theme/class-name/resolve-theme-from-class-name.cjs.map +0 -1
  302. package/dist/theme/class-name/resolve-theme-from-class-name.mjs +0 -22
  303. package/dist/theme/class-name/resolve-theme-from-class-name.mjs.map +0 -1
  304. package/dist/theme/data-attribute/apply-theme-to-data-attribute.cjs +0 -23
  305. package/dist/theme/data-attribute/apply-theme-to-data-attribute.cjs.map +0 -1
  306. package/dist/theme/data-attribute/apply-theme-to-data-attribute.mjs +0 -22
  307. package/dist/theme/data-attribute/apply-theme-to-data-attribute.mjs.map +0 -1
  308. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.cjs +0 -23
  309. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.cjs.map +0 -1
  310. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.mjs +0 -22
  311. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.mjs.map +0 -1
  312. package/src/theme/class-name/apply-theme-to-class-name.ts +0 -26
  313. package/src/theme/class-name/resolve-theme-from-class-name.ts +0 -22
  314. package/src/theme/data-attribute/apply-theme-to-data-attribute.ts +0 -27
  315. package/src/theme/data-attribute/resolve-theme-from-data-attribute.ts +0 -23
package/dist/theme.d.cts CHANGED
@@ -1,9 +1,27 @@
1
- import { ThemeMap } from "./theme/theme-map.types.cjs";
2
- import { ThemeEntry } from "./theme/theme-entry.types.cjs";
1
+ import { ThemeMap, ThemeMapValue } from "./theme/theme-map.types.cjs";
2
+ import { ParseStoredTheme, StringifyStoredTheme, ThemeEntry } from "./theme/theme-entry.types.cjs";
3
3
  import { AsyncThemeStore } from "./theme/theme-store/async-theme-store.types.cjs";
4
4
  import { ThemeStore } from "./theme/theme-store/theme-store.types.cjs";
5
5
  import { ThemeStoreFactory } from "./theme/theme-store/theme-store-factory.types.cjs";
6
6
  import { ComposeThemeStoreEntry, ComposeThemeStoresOptions, composeThemeStores } from "./theme/compose-theme-stores.cjs";
7
+ import { parseClassName } from "./theme/class-name/parse-class-name.cjs";
8
+ import { readClassName } from "./theme/class-name/read-class-name.cjs";
9
+ import { stringifyClassName } from "./theme/class-name/stringify-class-name.cjs";
10
+ import { subscribeClassName } from "./theme/class-name/subscribe-class-name.cjs";
11
+ import { writeClassName } from "./theme/class-name/write-class-name.cjs";
12
+ import { ReadCookieThemeOptions, readCookieTheme } from "./theme/cookie/read-cookie-theme.cjs";
13
+ import { WriteCookieThemeOptions, writeCookieTheme } from "./theme/cookie/write-cookie-theme.cjs";
14
+ import { parseDataAttribute } from "./theme/data-attribute/parse-data-attribute.cjs";
15
+ import { readDataAttribute } from "./theme/data-attribute/read-data-attribute.cjs";
16
+ import { stringifyDataAttribute } from "./theme/data-attribute/stringify-data-attribute.cjs";
17
+ import { subscribeDataAttribute } from "./theme/data-attribute/subscribe-data-attribute.cjs";
18
+ import { writeDataAttribute } from "./theme/data-attribute/write-data-attribute.cjs";
19
+ import { readLocalStorage } from "./theme/local-storage/read-local-storage.cjs";
20
+ import { writeLocalStorage } from "./theme/local-storage/write-local-storage.cjs";
21
+ import { ReadPrefersColorSchemeThemeOptions, readPrefersColorSchemeTheme } from "./theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.cjs";
22
+ import { subscribePrefersColorSchemeTheme } from "./theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.cjs";
23
+ import { readSessionStorage } from "./theme/session-storage/read-session-storage.cjs";
24
+ import { writeSessionStorage } from "./theme/session-storage/write-session-storage.cjs";
7
25
  import { themeEntry } from "./theme/theme-entry.cjs";
8
26
  import { classNameThemeStore } from "./theme/theme-store/class-name-theme-store/class-name-theme-store.cjs";
9
27
  import { CookieThemeStoreOptions, cookieThemeStore, getThemeFromCookie } from "./theme/theme-store/cookie-theme-store/cookie-theme-store.cjs";
@@ -12,4 +30,6 @@ import { inMemoryThemeStore } from "./theme/theme-store/in-memory-theme-store/in
12
30
  import { localStorageThemeStore } from "./theme/theme-store/local-storage-theme-store/local-storage-theme-store.cjs";
13
31
  import { prefersColorSchemeThemeStore } from "./theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.cjs";
14
32
  import { sessionStorageThemeStore } from "./theme/theme-store/session-storage-theme-store/session-storage-theme-store.cjs";
15
- export { AsyncThemeStore, ComposeThemeStoreEntry, ComposeThemeStoresOptions, CookieThemeStoreOptions, ThemeEntry, ThemeMap, ThemeStore, ThemeStoreFactory, classNameThemeStore, composeThemeStores, cookieThemeStore, dataAttributeThemeStore, getThemeFromCookie, inMemoryThemeStore, localStorageThemeStore, prefersColorSchemeThemeStore, sessionStorageThemeStore, themeEntry };
33
+ import { readWebStorage } from "./theme/web-storage/read-web-storage.cjs";
34
+ import { writeWebStorage } from "./theme/web-storage/write-web-storage.cjs";
35
+ export { AsyncThemeStore, ComposeThemeStoreEntry, ComposeThemeStoresOptions, CookieThemeStoreOptions, ParseStoredTheme, ReadCookieThemeOptions, ReadPrefersColorSchemeThemeOptions, StringifyStoredTheme, ThemeEntry, ThemeMap, ThemeMapValue, ThemeStore, ThemeStoreFactory, WriteCookieThemeOptions, classNameThemeStore, composeThemeStores, cookieThemeStore, dataAttributeThemeStore, getThemeFromCookie, inMemoryThemeStore, localStorageThemeStore, parseClassName, parseDataAttribute, prefersColorSchemeThemeStore, readClassName, readCookieTheme, readDataAttribute, readLocalStorage, readPrefersColorSchemeTheme, readSessionStorage, readWebStorage, sessionStorageThemeStore, stringifyClassName, stringifyDataAttribute, subscribeClassName, subscribeDataAttribute, subscribePrefersColorSchemeTheme, themeEntry, writeClassName, writeCookieTheme, writeDataAttribute, writeLocalStorage, writeSessionStorage, writeWebStorage };
package/dist/theme.d.mts CHANGED
@@ -1,9 +1,27 @@
1
- import { ThemeMap } from "./theme/theme-map.types.mjs";
2
- import { ThemeEntry } from "./theme/theme-entry.types.mjs";
1
+ import { ThemeMap, ThemeMapValue } from "./theme/theme-map.types.mjs";
2
+ import { ParseStoredTheme, StringifyStoredTheme, ThemeEntry } from "./theme/theme-entry.types.mjs";
3
3
  import { AsyncThemeStore } from "./theme/theme-store/async-theme-store.types.mjs";
4
4
  import { ThemeStore } from "./theme/theme-store/theme-store.types.mjs";
5
5
  import { ThemeStoreFactory } from "./theme/theme-store/theme-store-factory.types.mjs";
6
6
  import { ComposeThemeStoreEntry, ComposeThemeStoresOptions, composeThemeStores } from "./theme/compose-theme-stores.mjs";
7
+ import { parseClassName } from "./theme/class-name/parse-class-name.mjs";
8
+ import { readClassName } from "./theme/class-name/read-class-name.mjs";
9
+ import { stringifyClassName } from "./theme/class-name/stringify-class-name.mjs";
10
+ import { subscribeClassName } from "./theme/class-name/subscribe-class-name.mjs";
11
+ import { writeClassName } from "./theme/class-name/write-class-name.mjs";
12
+ import { ReadCookieThemeOptions, readCookieTheme } from "./theme/cookie/read-cookie-theme.mjs";
13
+ import { WriteCookieThemeOptions, writeCookieTheme } from "./theme/cookie/write-cookie-theme.mjs";
14
+ import { parseDataAttribute } from "./theme/data-attribute/parse-data-attribute.mjs";
15
+ import { readDataAttribute } from "./theme/data-attribute/read-data-attribute.mjs";
16
+ import { stringifyDataAttribute } from "./theme/data-attribute/stringify-data-attribute.mjs";
17
+ import { subscribeDataAttribute } from "./theme/data-attribute/subscribe-data-attribute.mjs";
18
+ import { writeDataAttribute } from "./theme/data-attribute/write-data-attribute.mjs";
19
+ import { readLocalStorage } from "./theme/local-storage/read-local-storage.mjs";
20
+ import { writeLocalStorage } from "./theme/local-storage/write-local-storage.mjs";
21
+ import { ReadPrefersColorSchemeThemeOptions, readPrefersColorSchemeTheme } from "./theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.mjs";
22
+ import { subscribePrefersColorSchemeTheme } from "./theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.mjs";
23
+ import { readSessionStorage } from "./theme/session-storage/read-session-storage.mjs";
24
+ import { writeSessionStorage } from "./theme/session-storage/write-session-storage.mjs";
7
25
  import { themeEntry } from "./theme/theme-entry.mjs";
8
26
  import { classNameThemeStore } from "./theme/theme-store/class-name-theme-store/class-name-theme-store.mjs";
9
27
  import { CookieThemeStoreOptions, cookieThemeStore, getThemeFromCookie } from "./theme/theme-store/cookie-theme-store/cookie-theme-store.mjs";
@@ -12,4 +30,6 @@ import { inMemoryThemeStore } from "./theme/theme-store/in-memory-theme-store/in
12
30
  import { localStorageThemeStore } from "./theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs";
13
31
  import { prefersColorSchemeThemeStore } from "./theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs";
14
32
  import { sessionStorageThemeStore } from "./theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs";
15
- export { AsyncThemeStore, ComposeThemeStoreEntry, ComposeThemeStoresOptions, CookieThemeStoreOptions, ThemeEntry, ThemeMap, ThemeStore, ThemeStoreFactory, classNameThemeStore, composeThemeStores, cookieThemeStore, dataAttributeThemeStore, getThemeFromCookie, inMemoryThemeStore, localStorageThemeStore, prefersColorSchemeThemeStore, sessionStorageThemeStore, themeEntry };
33
+ import { readWebStorage } from "./theme/web-storage/read-web-storage.mjs";
34
+ import { writeWebStorage } from "./theme/web-storage/write-web-storage.mjs";
35
+ export { AsyncThemeStore, ComposeThemeStoreEntry, ComposeThemeStoresOptions, CookieThemeStoreOptions, ParseStoredTheme, ReadCookieThemeOptions, ReadPrefersColorSchemeThemeOptions, StringifyStoredTheme, ThemeEntry, ThemeMap, ThemeMapValue, ThemeStore, ThemeStoreFactory, WriteCookieThemeOptions, classNameThemeStore, composeThemeStores, cookieThemeStore, dataAttributeThemeStore, getThemeFromCookie, inMemoryThemeStore, localStorageThemeStore, parseClassName, parseDataAttribute, prefersColorSchemeThemeStore, readClassName, readCookieTheme, readDataAttribute, readLocalStorage, readPrefersColorSchemeTheme, readSessionStorage, readWebStorage, sessionStorageThemeStore, stringifyClassName, stringifyDataAttribute, subscribeClassName, subscribeDataAttribute, subscribePrefersColorSchemeTheme, themeEntry, writeClassName, writeCookieTheme, writeDataAttribute, writeLocalStorage, writeSessionStorage, writeWebStorage };
package/dist/theme.mjs CHANGED
@@ -1,11 +1,31 @@
1
1
  import { themeEntry } from "./theme/theme-entry.mjs";
2
+ import { parseClassName } from "./theme/class-name/parse-class-name.mjs";
3
+ import { readClassName } from "./theme/class-name/read-class-name.mjs";
4
+ import { stringifyClassName } from "./theme/class-name/stringify-class-name.mjs";
5
+ import { subscribeClassName } from "./theme/class-name/subscribe-class-name.mjs";
6
+ import { writeClassName } from "./theme/class-name/write-class-name.mjs";
2
7
  import { classNameThemeStore } from "./theme/theme-store/class-name-theme-store/class-name-theme-store.mjs";
8
+ import { parseDataAttribute } from "./theme/data-attribute/parse-data-attribute.mjs";
9
+ import { readDataAttribute } from "./theme/data-attribute/read-data-attribute.mjs";
10
+ import { stringifyDataAttribute } from "./theme/data-attribute/stringify-data-attribute.mjs";
11
+ import { subscribeDataAttribute } from "./theme/data-attribute/subscribe-data-attribute.mjs";
12
+ import { writeDataAttribute } from "./theme/data-attribute/write-data-attribute.mjs";
3
13
  import { dataAttributeThemeStore } from "./theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs";
14
+ import { readWebStorage } from "./theme/web-storage/read-web-storage.mjs";
15
+ import { readLocalStorage } from "./theme/local-storage/read-local-storage.mjs";
16
+ import { writeWebStorage } from "./theme/web-storage/write-web-storage.mjs";
17
+ import { writeLocalStorage } from "./theme/local-storage/write-local-storage.mjs";
4
18
  import { localStorageThemeStore } from "./theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs";
5
19
  import { composeThemeStores } from "./theme/compose-theme-stores.mjs";
20
+ import { readCookieTheme } from "./theme/cookie/read-cookie-theme.mjs";
21
+ import { writeCookieTheme } from "./theme/cookie/write-cookie-theme.mjs";
22
+ import { readPrefersColorSchemeTheme } from "./theme/prefers-color-scheme-theme/read-prefers-color-scheme-theme.mjs";
23
+ import { subscribePrefersColorSchemeTheme } from "./theme/prefers-color-scheme-theme/subscribe-prefers-color-scheme-theme.mjs";
24
+ import { readSessionStorage } from "./theme/session-storage/read-session-storage.mjs";
25
+ import { writeSessionStorage } from "./theme/session-storage/write-session-storage.mjs";
6
26
  import { cookieThemeStore, getThemeFromCookie } from "./theme/theme-store/cookie-theme-store/cookie-theme-store.mjs";
7
27
  import { inMemoryThemeStore } from "./theme/theme-store/in-memory-theme-store/in-memory-theme-store.mjs";
8
28
  import { prefersColorSchemeThemeStore } from "./theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs";
9
29
  import { sessionStorageThemeStore } from "./theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs";
10
30
 
11
- export { classNameThemeStore, composeThemeStores, cookieThemeStore, dataAttributeThemeStore, getThemeFromCookie, inMemoryThemeStore, localStorageThemeStore, prefersColorSchemeThemeStore, sessionStorageThemeStore, themeEntry };
31
+ export { classNameThemeStore, composeThemeStores, cookieThemeStore, dataAttributeThemeStore, getThemeFromCookie, inMemoryThemeStore, localStorageThemeStore, parseClassName, parseDataAttribute, prefersColorSchemeThemeStore, readClassName, readCookieTheme, readDataAttribute, readLocalStorage, readPrefersColorSchemeTheme, readSessionStorage, readWebStorage, sessionStorageThemeStore, stringifyClassName, stringifyDataAttribute, subscribeClassName, subscribeDataAttribute, subscribePrefersColorSchemeTheme, themeEntry, writeClassName, writeCookieTheme, writeDataAttribute, writeLocalStorage, writeSessionStorage, writeWebStorage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@just-web/toolkits",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "Toolkits for web applications",
5
5
  "homepage": "https://github.com/justland/just-web-foundation/tree/main/libs/toolkits",
6
6
  "repository": {
@@ -1,7 +1,6 @@
1
1
  import { useCallback, useEffect, useMemo, useState } from 'react'
2
2
  import { observeThemeFromStores } from '../../theme/_utils/observe-theme-from-stores.ts'
3
3
  import { setThemeToStores } from '../../theme/_utils/set-theme-to-stores.ts'
4
- import { resolveThemeFromClassName } from '../../theme/class-name/resolve-theme-from-class-name.ts'
5
4
  import { themeEntry } from '../../theme/theme-entry.ts'
6
5
  import type { ThemeMap } from '../../theme/theme-map.types.ts'
7
6
  import { classNameThemeStore } from '../../theme/theme-store/class-name-theme-store/class-name-theme-store.ts'
@@ -42,13 +41,9 @@ export function useThemeByClassName<Themes extends ThemeMap>(
42
41
 
43
42
  const store = useMemo(() => classNameThemeStore(themes, { element }), [element, themes])
44
43
 
45
- const [theme, setThemeState] = useState<keyof Themes | undefined>(() => {
46
- if (element) {
47
- const resolved = resolveThemeFromClassName(themes, element.className)
48
- return resolved ?? defaultTheme
49
- }
50
- return defaultTheme
51
- })
44
+ const [theme, setThemeState] = useState<keyof Themes | undefined>(
45
+ () => store.read()?.theme ?? defaultTheme
46
+ )
52
47
 
53
48
  useEffect(() => {
54
49
  if (!element) return
@@ -1,8 +1,6 @@
1
1
  import { useCallback, useEffect, useMemo, useState } from 'react'
2
- import { getDataAttribute } from '../../attributes/get-data-attribute.ts'
3
2
  import { observeThemeFromStores } from '../../theme/_utils/observe-theme-from-stores.ts'
4
3
  import { setThemeToStores } from '../../theme/_utils/set-theme-to-stores.ts'
5
- import { resolveThemeFromDataAttribute } from '../../theme/data-attribute/resolve-theme-from-data-attribute.ts'
6
4
  import { themeEntry } from '../../theme/theme-entry.ts'
7
5
  import type { ThemeMap } from '../../theme/theme-map.types.ts'
8
6
  import { dataAttributeThemeStore } from '../../theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.ts'
@@ -56,14 +54,9 @@ export function useThemeByDataAttribute<Themes extends ThemeMap>(
56
54
  [element, themes, attributeName]
57
55
  )
58
56
 
59
- const [theme, setThemeState] = useState<keyof Themes | undefined>(() => {
60
- if (element) {
61
- const attrValue = getDataAttribute(attributeName, element)
62
- const resolved = resolveThemeFromDataAttribute(themes, attrValue)
63
- return resolved ?? defaultTheme
64
- }
65
- return defaultTheme
66
- })
57
+ const [theme, setThemeState] = useState<keyof Themes | undefined>(
58
+ () => store.read()?.theme ?? defaultTheme
59
+ )
67
60
 
68
61
  useEffect(() => {
69
62
  if (!element) return
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useEffect, useMemo, useState } from 'react'
2
2
  import { observeThemeFromStores } from '../../theme/_utils/observe-theme-from-stores.ts'
3
- import { parseStoredTheme } from '../../theme/_utils/parse-stored-theme.ts'
4
3
  import { setThemeToStores } from '../../theme/_utils/set-theme-to-stores.ts'
5
4
  import { themeEntry } from '../../theme/theme-entry.ts'
6
5
  import type { ThemeMap } from '../../theme/theme-map.types.ts'
@@ -43,14 +42,9 @@ export function useThemeByLocalStorage<Themes extends ThemeMap>(
43
42
 
44
43
  const store = useMemo(() => localStorageThemeStore(themes, { storageKey }), [themes, storageKey])
45
44
 
46
- const [theme, setThemeState] = useState<keyof Themes | undefined>(() => {
47
- if (typeof window !== 'undefined' && window.localStorage) {
48
- const stored = window.localStorage.getItem(storageKey)
49
- const resolved = parseStoredTheme(themes, stored)
50
- return resolved ?? defaultTheme
51
- }
52
- return defaultTheme
53
- })
45
+ const [theme, setThemeState] = useState<keyof Themes | undefined>(
46
+ () => store.read()?.theme ?? defaultTheme
47
+ )
54
48
 
55
49
  useEffect(() => {
56
50
  const unobserve = observeThemeFromStores([store], defaultTheme, setThemeState)
@@ -16,6 +16,7 @@ function formatValue(value: unknown): string {
16
16
  if (value === null) return '(missing)'
17
17
  if (value === '') return '(empty)'
18
18
  if (Array.isArray(value)) return `[${value.join(', ')}]`
19
+ if (typeof value === 'object' && value !== null) return JSON.stringify(value)
19
20
  return String(value)
20
21
  }
21
22
 
@@ -0,0 +1,36 @@
1
+ import { findKey } from 'type-plus'
2
+ import type { ThemeMap } from '../theme-map.types.ts'
3
+ import { resolveThemeMapValue } from './resolve-theme-map-value.ts'
4
+
5
+ /**
6
+ * Matches an attribute value string against the theme map and returns the theme key.
7
+ * Pure function: no DOM access. Used by parseDataAttribute and custom parse paths.
8
+ *
9
+ * @param themes - Record mapping theme keys to attribute values
10
+ * @param attrValue - Attribute value string (e.g. from getAttribute)
11
+ * @param options.separator - When defined, split by separator and use first token
12
+ * @returns Theme key if a match is found, otherwise undefined
13
+ */
14
+ export function matchAttributeValueToTheme<Theme extends string>(
15
+ themes: ThemeMap<Theme>,
16
+ attrValue: string | null,
17
+ options?: { separator?: string | undefined } | undefined
18
+ ): Theme | undefined {
19
+ if (attrValue === null || attrValue === '') return undefined
20
+ const valueToMatch =
21
+ options?.separator !== undefined
22
+ ? attrValue
23
+ .trim()
24
+ .split(options.separator)
25
+ .find((s) => s.trim() !== '')
26
+ : attrValue
27
+ if (valueToMatch === undefined) return undefined
28
+ const theme = findKey(themes, (key) => {
29
+ const value = themes[key]
30
+ if (value === undefined) return false
31
+ const resolved = resolveThemeMapValue(value)
32
+ const v = Array.isArray(resolved) ? resolved[0] : resolved
33
+ return v === valueToMatch
34
+ })
35
+ return theme
36
+ }
@@ -1,21 +1,61 @@
1
1
  import { tryParseJSON } from '../../_internal/utils/try-parse-json.ts'
2
- import type { ThemeMap } from '../theme-map.types.ts'
2
+ import type { ThemeEntry } from '../theme-entry.types.ts'
3
+ import type { ThemeMap, ThemeMapValue } from '../theme-map.types.ts'
4
+ import { isReadonlyStringArray } from './resolve-theme-map-value.ts'
5
+
6
+ type Shape = 'string' | 'array' | 'object-string' | 'object-array'
7
+
8
+ function getShapeAndComparable(
9
+ v: unknown
10
+ ): { shape: Shape; comparable: string | undefined } | null {
11
+ if (typeof v === 'string') return { shape: 'string', comparable: v }
12
+ if (Array.isArray(v)) return { shape: 'array', comparable: v[0] }
13
+ if (v !== null && typeof v === 'object' && 'themeValue' in v) {
14
+ const tv = (v as { themeValue: string | string[] }).themeValue
15
+ if (typeof tv === 'string') return { shape: 'object-string', comparable: tv }
16
+ if (Array.isArray(tv)) return { shape: 'object-array', comparable: tv[0] }
17
+ }
18
+ return null
19
+ }
20
+
21
+ function getCanonicalShapeAndComparable(v: ThemeMapValue): {
22
+ shape: Shape
23
+ comparable: string | undefined
24
+ } {
25
+ if (typeof v === 'string') return { shape: 'string', comparable: v }
26
+ if (isReadonlyStringArray(v)) return { shape: 'array', comparable: v[0] }
27
+ const tv = v.themeValue
28
+ if (typeof tv === 'string') return { shape: 'object-string', comparable: tv }
29
+ return { shape: 'object-array', comparable: tv[0] }
30
+ }
3
31
 
4
32
  /**
5
- * Parses stored JSON theme and validates the theme key against theme map.
33
+ * Parses stored JSON theme and validates against theme map with strict shape and comparable matching.
6
34
  *
7
35
  * Expects stored shape: { theme: string, value?: unknown }
8
36
  *
9
- * @param themes - Record of valid theme keys (optional; if omitted, any theme string is accepted)
10
- * @param value - Raw string from localStorage/sessionStorage
11
- * @returns Theme key if valid, otherwise undefined
37
+ * When shape matches AND comparable value (string or [0]) matches themes[theme]:
38
+ * returns { theme, value: stored.value }. Else returns undefined.
39
+ *
40
+ * @param themes - Record of valid theme keys and values (required for validation)
41
+ * @param value - Raw string from localStorage/sessionStorage/cookie
42
+ * @returns ThemeEntry when valid, otherwise undefined
12
43
  */
13
- export function parseStoredTheme<Theme extends string>(
14
- themes: ThemeMap<Theme> | undefined,
15
- value: string | null | undefined
16
- ): Theme | undefined {
17
- const parsed = tryParseJSON<{ theme: string }>(value)
44
+ export function parseStoredTheme<Themes extends ThemeMap>(
45
+ themes: Themes | undefined,
46
+ value: string | undefined
47
+ ): ThemeEntry<Themes> | undefined {
48
+ const parsed = tryParseJSON<{ theme: string; value?: unknown }>(value ?? null)
18
49
  if (!parsed?.theme || typeof parsed.theme !== 'string') return undefined
19
- if (themes && !(parsed.theme in themes)) return undefined
20
- return parsed.theme as Theme
50
+ if (!themes || !(parsed.theme in themes)) return undefined
51
+ if (parsed.value === undefined) return undefined
52
+
53
+ const storedInfo = getShapeAndComparable(parsed.value)
54
+ if (!storedInfo) return undefined
55
+
56
+ const canonical = getCanonicalShapeAndComparable(themes[parsed.theme] as ThemeMapValue)
57
+ if (storedInfo.shape !== canonical.shape) return undefined
58
+ if (storedInfo.comparable !== canonical.comparable) return undefined
59
+
60
+ return { theme: parsed.theme as keyof Themes, value: parsed.value as Themes[keyof Themes] }
21
61
  }
@@ -0,0 +1,15 @@
1
+ import type { ThemeMapValue } from '../theme-map.types.ts'
2
+
3
+ export function isReadonlyStringArray(v: ThemeMapValue): v is readonly string[] {
4
+ return Array.isArray(v)
5
+ }
6
+
7
+ /**
8
+ * Resolves ThemeMapValue to its underlying string or string[] for DOM application and matching.
9
+ * Used when applying themes to className, data attributes, or when resolving theme from DOM.
10
+ */
11
+ export function resolveThemeMapValue(v: ThemeMapValue): string | readonly string[] {
12
+ if (typeof v === 'string') return v
13
+ if (isReadonlyStringArray(v)) return v
14
+ return v.themeValue
15
+ }
@@ -0,0 +1,31 @@
1
+ import { findKey } from 'type-plus'
2
+ import { resolveThemeMapValue } from '../_utils/resolve-theme-map-value.ts'
3
+ import { themeEntry } from '../theme-entry.ts'
4
+ import type { ThemeEntry } from '../theme-entry.types.ts'
5
+ import type { ThemeMap } from '../theme-map.types.ts'
6
+
7
+ /**
8
+ * Parses a class name string into a ThemeEntry.
9
+ *
10
+ * Pure function: no DOM access. Matches class strings by checking if any theme
11
+ * class is included in the className (e.g. `className.includes(themeClass)`).
12
+ * Arrays in theme map use first value for matching.
13
+ *
14
+ * @param themes - Record mapping theme keys to class name(s)
15
+ * @param className - Raw class attribute value (e.g. from element.className)
16
+ * @returns ThemeEntry if a match is found, otherwise undefined
17
+ */
18
+ export function parseClassName<Themes extends ThemeMap>(
19
+ themes: Themes,
20
+ className: string | undefined
21
+ ): ThemeEntry<Themes> | undefined {
22
+ const cls = className ?? ''
23
+ const theme = findKey(themes, (key) => {
24
+ const value = themes[key]
25
+ if (value === undefined) return false
26
+ const resolved = resolveThemeMapValue(value)
27
+ const v = Array.isArray(resolved) ? resolved[0] : resolved
28
+ return !!v && cls.includes(v)
29
+ })
30
+ return theme !== undefined ? themeEntry(themes, theme) : undefined
31
+ }
@@ -0,0 +1,24 @@
1
+ import type { ParseStoredTheme, ThemeEntry } from '../theme-entry.types.ts'
2
+ import type { ThemeMap } from '../theme-map.types.ts'
3
+ import { parseClassName } from './parse-class-name.ts'
4
+
5
+ /**
6
+ * Reads a theme entry from the class attribute on an element.
7
+ *
8
+ * @param themes - Record mapping theme keys to class name(s)
9
+ * @param options.element - Element to read from (defaults to document.documentElement)
10
+ * @param options.parse - Custom parser (default: parseClassName)
11
+ * @returns ThemeEntry if found, undefined otherwise. Returns undefined when element is not available (e.g. SSR).
12
+ */
13
+ export function readClassName<Themes extends ThemeMap>(
14
+ themes: Themes,
15
+ options?:
16
+ | { element?: Element | undefined; parse?: ParseStoredTheme<Themes> | undefined }
17
+ | undefined
18
+ ): ThemeEntry<Themes> | undefined {
19
+ const element = options?.element ?? document?.documentElement
20
+ if (!element) return undefined
21
+ const parse = options?.parse ?? parseClassName
22
+ const raw = element.className ?? undefined
23
+ return parse(themes, raw)
24
+ }
@@ -0,0 +1,36 @@
1
+ import { resolveThemeMapValue } from '../_utils/resolve-theme-map-value.ts'
2
+ import type { ThemeEntry } from '../theme-entry.types.ts'
3
+ import type { ThemeMap } from '../theme-map.types.ts'
4
+
5
+ /**
6
+ * Stringifies a ThemeEntry for a class attribute value.
7
+ *
8
+ * Pure function: no DOM access. Removes all theme classes from existing, then
9
+ * adds entry's class(es). Applies all classes from entry when value is an array
10
+ * (unlike stringifyDataAttribute which uses first only).
11
+ *
12
+ * @param themes - Record mapping theme keys to class names (used to identify theme tokens)
13
+ * @param existing - Current class attribute value string
14
+ * @param entry - Theme entry to stringify, or undefined to clear theme (keeps non-theme classes)
15
+ * @returns Class attribute value string
16
+ */
17
+ export function stringifyClassName<Themes extends ThemeMap>(
18
+ themes: Themes,
19
+ existing: string | undefined,
20
+ entry: ThemeEntry<Themes> | undefined
21
+ ): string {
22
+ const allThemeClasses = Object.values(themes).flatMap((v) => {
23
+ const resolved = resolveThemeMapValue(v)
24
+ return Array.isArray(resolved) ? [...resolved] : [resolved]
25
+ })
26
+ const existingClasses = existing?.trim() ? existing.trim().split(/\s+/) : []
27
+ const withoutThemes = existingClasses.filter((c) => !allThemeClasses.includes(c))
28
+ const activeClasses =
29
+ entry !== undefined
30
+ ? (() => {
31
+ const resolved = resolveThemeMapValue(entry.value)
32
+ return Array.isArray(resolved) ? [...resolved] : [resolved]
33
+ })()
34
+ : []
35
+ return [...withoutThemes, ...activeClasses].filter(Boolean).join(' ')
36
+ }
@@ -0,0 +1,39 @@
1
+ import { observeAttributes } from '../../attributes/observe-attribute.ts'
2
+ import type { ParseStoredTheme, ThemeEntry } from '../theme-entry.types.ts'
3
+ import type { ThemeMap } from '../theme-map.types.ts'
4
+ import { parseClassName } from './parse-class-name.ts'
5
+
6
+ /**
7
+ * Subscribes to changes on the class attribute and invokes the handler with parsed theme entries.
8
+ *
9
+ * @param themes - Record mapping theme keys to class name(s)
10
+ * @param handler - Callback invoked when the class attribute changes
11
+ * @param options.element - Element to observe (defaults to document.documentElement)
12
+ * @param options.parse - Custom parser (default: parseClassName)
13
+ * @returns Unsubscribe function. Returns a no-op function when element is not available (e.g. SSR).
14
+ */
15
+ export function subscribeClassName<Themes extends ThemeMap>(
16
+ themes: Themes,
17
+ handler: (entry: ThemeEntry<Themes> | undefined) => void,
18
+ options?:
19
+ | { element?: Element | undefined; parse?: ParseStoredTheme<Themes> | undefined }
20
+ | undefined
21
+ ): () => void {
22
+ const element = options?.element ?? document?.documentElement
23
+ if (!element) return () => {}
24
+ const parse = options?.parse ?? parseClassName
25
+ let lastEmitted: keyof Themes | undefined | null = null
26
+ const observer = observeAttributes(
27
+ {
28
+ class: (value) => {
29
+ const entry = parse(themes, value ?? undefined)
30
+ const key = entry?.theme ?? undefined
31
+ if (lastEmitted === key) return
32
+ lastEmitted = key
33
+ handler(entry)
34
+ }
35
+ },
36
+ element
37
+ )
38
+ return () => observer.disconnect()
39
+ }
@@ -0,0 +1,24 @@
1
+ import type { StringifyStoredTheme, ThemeEntry } from '../theme-entry.types.ts'
2
+ import type { ThemeMap } from '../theme-map.types.ts'
3
+ import { stringifyClassName } from './stringify-class-name.ts'
4
+
5
+ /**
6
+ * Writes a theme entry to the class attribute on an element.
7
+ *
8
+ * @param themes - Record mapping theme keys to class name(s)
9
+ * @param entry - Theme entry to write, or undefined to remove the theme
10
+ * @param options.element - Element to write to (defaults to document.documentElement)
11
+ * @param options.stringify - Custom serializer (default: stringifyClassName)
12
+ */
13
+ export function writeClassName<Themes extends ThemeMap>(
14
+ themes: Themes,
15
+ entry: ThemeEntry<Themes> | undefined,
16
+ options?:
17
+ | { element?: Element | undefined; stringify?: StringifyStoredTheme<Themes> | undefined }
18
+ | undefined
19
+ ): void {
20
+ const element = options?.element ?? document?.documentElement
21
+ if (!element) return
22
+ const stringify = options?.stringify ?? stringifyClassName
23
+ element.className = stringify(themes, element.className ?? undefined, entry)
24
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Internal cookie utilities for theme cookie storage.
3
+ * Cookie Store API has limited support; document.cookie is standard for theme persistence.
4
+ */
5
+
6
+ export function getCookieValue(name: string): string | null {
7
+ if (typeof document === 'undefined' || !document.cookie) return null
8
+ const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))
9
+ const value = match?.[1]
10
+ return value !== undefined ? decodeURIComponent(value) : null
11
+ }
12
+
13
+ export function setCookie(
14
+ name: string,
15
+ value: string,
16
+ options: {
17
+ path?: string | undefined
18
+ maxAge?: number | undefined
19
+ sameSite?: 'lax' | 'strict' | 'none' | undefined
20
+ secure?: boolean | undefined
21
+ }
22
+ ) {
23
+ const parts = [`${name}=${encodeURIComponent(value)}`]
24
+ parts.push(`path=${options.path ?? '/'}`)
25
+ if (options.maxAge !== undefined) parts.push(`max-age=${options.maxAge}`)
26
+ if (options.sameSite !== undefined) parts.push(`samesite=${options.sameSite}`)
27
+ if (options.secure) parts.push('secure')
28
+ // biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API has limited support; document.cookie is standard for theme persistence
29
+ document.cookie = parts.join('; ')
30
+ }
31
+
32
+ export function deleteCookie(name: string, path = '/') {
33
+ // biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API has limited support; document.cookie is standard for theme persistence
34
+ document.cookie = `${name}=; path=${path}; max-age=0`
35
+ }
36
+
37
+ /**
38
+ * Parses a cookie value from a raw Cookie header string.
39
+ * Used for SSR when reading from request headers or framework cookie APIs.
40
+ */
41
+ export function getCookieFromHeader(cookieHeader: string, name: string): string | null {
42
+ const match = cookieHeader.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))
43
+ const value = match?.[1]
44
+ return value !== undefined ? decodeURIComponent(value.trim()) : null
45
+ }
@@ -0,0 +1,33 @@
1
+ import { parseStoredTheme } from '../_utils/parse-stored-theme.ts'
2
+ import type { ParseStoredTheme, ThemeEntry } from '../theme-entry.types.ts'
3
+ import type { ThemeMap } from '../theme-map.types.ts'
4
+ import { getCookieValue } from './_cookie-utils.ts'
5
+
6
+ export interface ReadCookieThemeOptions<Themes extends ThemeMap = ThemeMap> {
7
+ cookieName: string
8
+ path?: string | undefined
9
+ parse?: ParseStoredTheme<Themes> | undefined
10
+ }
11
+
12
+ /**
13
+ * Reads a theme entry from a cookie.
14
+ *
15
+ * @param themes - Record mapping theme keys to values (for validation)
16
+ * @param options.cookieName - Cookie name to read from
17
+ * @param options.path - Cookie path (default: '/')
18
+ * @param options.parse - Custom parser (default: parseStoredTheme)
19
+ * @returns ThemeEntry if found, undefined otherwise. Returns undefined when document.cookie is unavailable (e.g. SSR).
20
+ */
21
+ export function readCookieTheme<Themes extends ThemeMap>(
22
+ themes: Themes,
23
+ options: ReadCookieThemeOptions<Themes>
24
+ ): ThemeEntry<Themes> | undefined {
25
+ const { cookieName, parse = parseStoredTheme } = options
26
+
27
+ if (typeof document === 'undefined' || document.cookie === undefined) {
28
+ return undefined
29
+ }
30
+
31
+ const stored = getCookieValue(cookieName)
32
+ return parse(themes, stored ?? undefined)
33
+ }
@@ -0,0 +1,48 @@
1
+ import type { ThemeEntry } from '../theme-entry.types.ts'
2
+ import type { ThemeMap } from '../theme-map.types.ts'
3
+ import { deleteCookie, setCookie } from './_cookie-utils.ts'
4
+
5
+ export interface WriteCookieThemeOptions<_Themes extends ThemeMap = ThemeMap> {
6
+ cookieName: string
7
+ path?: string | undefined
8
+ maxAge?: number | undefined
9
+ sameSite?: 'lax' | 'strict' | 'none' | undefined
10
+ secure?: boolean | undefined
11
+ }
12
+
13
+ /**
14
+ * Writes a theme entry to a cookie.
15
+ *
16
+ * Performs cookie set/delete only. Does not notify subscribers; the store must call notify() after this.
17
+ *
18
+ * @param themes - Record mapping theme keys to values (used for type validation)
19
+ * @param entry - Theme entry to write, or undefined to remove
20
+ * @param options - Cookie options
21
+ */
22
+ export function writeCookieTheme<Themes extends ThemeMap>(
23
+ _themes: Themes,
24
+ entry: ThemeEntry<Themes> | undefined,
25
+ options: WriteCookieThemeOptions<Themes>
26
+ ): void {
27
+ const { cookieName, path = '/', maxAge, sameSite, secure } = options
28
+
29
+ if (typeof document === 'undefined' || document.cookie === undefined) {
30
+ return
31
+ }
32
+
33
+ if (entry === undefined) {
34
+ deleteCookie(cookieName, path)
35
+ return
36
+ }
37
+
38
+ const opts: {
39
+ path: string
40
+ maxAge?: number
41
+ sameSite?: 'lax' | 'strict' | 'none'
42
+ secure?: boolean
43
+ } = { path }
44
+ if (maxAge !== undefined) opts.maxAge = maxAge
45
+ if (sameSite !== undefined) opts.sameSite = sameSite
46
+ if (secure) opts.secure = true
47
+ setCookie(cookieName, JSON.stringify(entry), opts)
48
+ }
@@ -0,0 +1 @@
1
+ export const SEPARATOR_SPACE = ' '