@just-web/toolkits 1.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 (449) hide show
  1. package/dist/_internal/utils/try-parse-json.cjs +14 -0
  2. package/dist/_internal/utils/try-parse-json.cjs.map +1 -0
  3. package/dist/_internal/utils/try-parse-json.mjs +13 -0
  4. package/dist/_internal/utils/try-parse-json.mjs.map +1 -0
  5. package/dist/_virtual/rolldown_runtime.cjs +29 -0
  6. package/dist/attributes/data-attribute.d.cts +17 -0
  7. package/dist/attributes/data-attribute.d.cts.map +1 -0
  8. package/dist/attributes/data-attribute.d.mts +17 -0
  9. package/dist/attributes/data-attribute.d.mts.map +1 -0
  10. package/dist/attributes/get-attribute.cjs +26 -0
  11. package/dist/attributes/get-attribute.cjs.map +1 -0
  12. package/dist/attributes/get-attribute.d.cts +21 -0
  13. package/dist/attributes/get-attribute.d.cts.map +1 -0
  14. package/dist/attributes/get-attribute.d.mts +21 -0
  15. package/dist/attributes/get-attribute.d.mts.map +1 -0
  16. package/dist/attributes/get-attribute.mjs +25 -0
  17. package/dist/attributes/get-attribute.mjs.map +1 -0
  18. package/dist/attributes/get-data-attribute.cjs +19 -0
  19. package/dist/attributes/get-data-attribute.cjs.map +1 -0
  20. package/dist/attributes/get-data-attribute.d.cts +17 -0
  21. package/dist/attributes/get-data-attribute.d.cts.map +1 -0
  22. package/dist/attributes/get-data-attribute.d.mts +17 -0
  23. package/dist/attributes/get-data-attribute.d.mts.map +1 -0
  24. package/dist/attributes/get-data-attribute.mjs +19 -0
  25. package/dist/attributes/get-data-attribute.mjs.map +1 -0
  26. package/dist/attributes/observe-attribute.cjs +40 -0
  27. package/dist/attributes/observe-attribute.cjs.map +1 -0
  28. package/dist/attributes/observe-attribute.d.cts +23 -0
  29. package/dist/attributes/observe-attribute.d.cts.map +1 -0
  30. package/dist/attributes/observe-attribute.d.mts +23 -0
  31. package/dist/attributes/observe-attribute.d.mts.map +1 -0
  32. package/dist/attributes/observe-attribute.mjs +39 -0
  33. package/dist/attributes/observe-attribute.mjs.map +1 -0
  34. package/dist/attributes/observe-data-attribute.cjs +31 -0
  35. package/dist/attributes/observe-data-attribute.cjs.map +1 -0
  36. package/dist/attributes/observe-data-attribute.d.cts +26 -0
  37. package/dist/attributes/observe-data-attribute.d.cts.map +1 -0
  38. package/dist/attributes/observe-data-attribute.d.mts +26 -0
  39. package/dist/attributes/observe-data-attribute.d.mts.map +1 -0
  40. package/dist/attributes/observe-data-attribute.mjs +31 -0
  41. package/dist/attributes/observe-data-attribute.mjs.map +1 -0
  42. package/dist/children/just-children.d.cts +37 -0
  43. package/dist/children/just-children.d.cts.map +1 -0
  44. package/dist/children/just-children.d.mts +37 -0
  45. package/dist/children/just-children.d.mts.map +1 -0
  46. package/dist/children/resolve-children.cjs +11 -0
  47. package/dist/children/resolve-children.cjs.map +1 -0
  48. package/dist/children/resolve-children.d.cts +9 -0
  49. package/dist/children/resolve-children.d.cts.map +1 -0
  50. package/dist/children/resolve-children.d.mts +9 -0
  51. package/dist/children/resolve-children.d.mts.map +1 -0
  52. package/dist/children/resolve-children.mjs +10 -0
  53. package/dist/children/resolve-children.mjs.map +1 -0
  54. package/dist/class-name/class-name-props.d.cts +11 -0
  55. package/dist/class-name/class-name-props.d.cts.map +1 -0
  56. package/dist/class-name/class-name-props.d.mts +11 -0
  57. package/dist/class-name/class-name-props.d.mts.map +1 -0
  58. package/dist/class-name/clsx.cjs +3 -0
  59. package/dist/class-name/clsx.d.cts +2 -0
  60. package/dist/class-name/clsx.d.mts +2 -0
  61. package/dist/class-name/clsx.mjs +3 -0
  62. package/dist/class-name/just-class-name.d.cts +36 -0
  63. package/dist/class-name/just-class-name.d.cts.map +1 -0
  64. package/dist/class-name/just-class-name.d.mts +36 -0
  65. package/dist/class-name/just-class-name.d.mts.map +1 -0
  66. package/dist/class-name/resolve-class-name.cjs +12 -0
  67. package/dist/class-name/resolve-class-name.cjs.map +1 -0
  68. package/dist/class-name/resolve-class-name.d.cts +8 -0
  69. package/dist/class-name/resolve-class-name.d.cts.map +1 -0
  70. package/dist/class-name/resolve-class-name.d.mts +8 -0
  71. package/dist/class-name/resolve-class-name.d.mts.map +1 -0
  72. package/dist/class-name/resolve-class-name.mjs +10 -0
  73. package/dist/class-name/resolve-class-name.mjs.map +1 -0
  74. package/dist/color-scheme/get-prefers-color-scheme.cjs +21 -0
  75. package/dist/color-scheme/get-prefers-color-scheme.cjs.map +1 -0
  76. package/dist/color-scheme/get-prefers-color-scheme.d.cts +16 -0
  77. package/dist/color-scheme/get-prefers-color-scheme.d.cts.map +1 -0
  78. package/dist/color-scheme/get-prefers-color-scheme.d.mts +16 -0
  79. package/dist/color-scheme/get-prefers-color-scheme.d.mts.map +1 -0
  80. package/dist/color-scheme/get-prefers-color-scheme.mjs +20 -0
  81. package/dist/color-scheme/get-prefers-color-scheme.mjs.map +1 -0
  82. package/dist/color-scheme/observe-prefers-color-scheme.cjs +29 -0
  83. package/dist/color-scheme/observe-prefers-color-scheme.cjs.map +1 -0
  84. package/dist/color-scheme/observe-prefers-color-scheme.d.cts +20 -0
  85. package/dist/color-scheme/observe-prefers-color-scheme.d.cts.map +1 -0
  86. package/dist/color-scheme/observe-prefers-color-scheme.d.mts +20 -0
  87. package/dist/color-scheme/observe-prefers-color-scheme.d.mts.map +1 -0
  88. package/dist/color-scheme/observe-prefers-color-scheme.mjs +28 -0
  89. package/dist/color-scheme/observe-prefers-color-scheme.mjs.map +1 -0
  90. package/dist/index.cjs +39 -0
  91. package/dist/index.d.cts +26 -0
  92. package/dist/index.d.mts +26 -0
  93. package/dist/index.mjs +20 -0
  94. package/dist/react/hooks/use-attribute.cjs +41 -0
  95. package/dist/react/hooks/use-attribute.cjs.map +1 -0
  96. package/dist/react/hooks/use-attribute.d.cts +21 -0
  97. package/dist/react/hooks/use-attribute.d.cts.map +1 -0
  98. package/dist/react/hooks/use-attribute.d.mts +21 -0
  99. package/dist/react/hooks/use-attribute.d.mts.map +1 -0
  100. package/dist/react/hooks/use-attribute.mjs +40 -0
  101. package/dist/react/hooks/use-attribute.mjs.map +1 -0
  102. package/dist/react/hooks/use-prefers-color-scheme.cjs +42 -0
  103. package/dist/react/hooks/use-prefers-color-scheme.cjs.map +1 -0
  104. package/dist/react/hooks/use-prefers-color-scheme.d.cts +29 -0
  105. package/dist/react/hooks/use-prefers-color-scheme.d.cts.map +1 -0
  106. package/dist/react/hooks/use-prefers-color-scheme.d.mts +29 -0
  107. package/dist/react/hooks/use-prefers-color-scheme.d.mts.map +1 -0
  108. package/dist/react/hooks/use-prefers-color-scheme.mjs +41 -0
  109. package/dist/react/hooks/use-prefers-color-scheme.mjs.map +1 -0
  110. package/dist/react/hooks/use-theme-by-class-name.cjs +60 -0
  111. package/dist/react/hooks/use-theme-by-class-name.cjs.map +1 -0
  112. package/dist/react/hooks/use-theme-by-class-name.d.cts +34 -0
  113. package/dist/react/hooks/use-theme-by-class-name.d.cts.map +1 -0
  114. package/dist/react/hooks/use-theme-by-class-name.d.mts +34 -0
  115. package/dist/react/hooks/use-theme-by-class-name.d.mts.map +1 -0
  116. package/dist/react/hooks/use-theme-by-class-name.mjs +59 -0
  117. package/dist/react/hooks/use-theme-by-class-name.mjs.map +1 -0
  118. package/dist/react/hooks/use-theme-by-data-attribute.cjs +73 -0
  119. package/dist/react/hooks/use-theme-by-data-attribute.cjs.map +1 -0
  120. package/dist/react/hooks/use-theme-by-data-attribute.d.cts +39 -0
  121. package/dist/react/hooks/use-theme-by-data-attribute.d.cts.map +1 -0
  122. package/dist/react/hooks/use-theme-by-data-attribute.d.mts +39 -0
  123. package/dist/react/hooks/use-theme-by-data-attribute.d.mts.map +1 -0
  124. package/dist/react/hooks/use-theme-by-data-attribute.mjs +72 -0
  125. package/dist/react/hooks/use-theme-by-data-attribute.mjs.map +1 -0
  126. package/dist/react/hooks/use-theme-by-local-storage.cjs +53 -0
  127. package/dist/react/hooks/use-theme-by-local-storage.cjs.map +1 -0
  128. package/dist/react/hooks/use-theme-by-local-storage.d.cts +37 -0
  129. package/dist/react/hooks/use-theme-by-local-storage.d.cts.map +1 -0
  130. package/dist/react/hooks/use-theme-by-local-storage.d.mts +37 -0
  131. package/dist/react/hooks/use-theme-by-local-storage.d.mts.map +1 -0
  132. package/dist/react/hooks/use-theme-by-local-storage.mjs +52 -0
  133. package/dist/react/hooks/use-theme-by-local-storage.mjs.map +1 -0
  134. package/dist/react/hooks/use-theme-stores.cjs +40 -0
  135. package/dist/react/hooks/use-theme-stores.cjs.map +1 -0
  136. package/dist/react/hooks/use-theme-stores.d.cts +38 -0
  137. package/dist/react/hooks/use-theme-stores.d.cts.map +1 -0
  138. package/dist/react/hooks/use-theme-stores.d.mts +38 -0
  139. package/dist/react/hooks/use-theme-stores.d.mts.map +1 -0
  140. package/dist/react/hooks/use-theme-stores.mjs +39 -0
  141. package/dist/react/hooks/use-theme-stores.mjs.map +1 -0
  142. package/dist/react/theme/create-theme-hook.cjs +105 -0
  143. package/dist/react/theme/create-theme-hook.cjs.map +1 -0
  144. package/dist/react/theme/create-theme-hook.d.cts +29 -0
  145. package/dist/react/theme/create-theme-hook.d.cts.map +1 -0
  146. package/dist/react/theme/create-theme-hook.d.mts +29 -0
  147. package/dist/react/theme/create-theme-hook.d.mts.map +1 -0
  148. package/dist/react/theme/create-theme-hook.mjs +104 -0
  149. package/dist/react/theme/create-theme-hook.mjs.map +1 -0
  150. package/dist/react.cjs +15 -0
  151. package/dist/react.d.cts +8 -0
  152. package/dist/react.d.mts +8 -0
  153. package/dist/react.mjs +9 -0
  154. package/dist/style/css-properties.d.cts +20 -0
  155. package/dist/style/css-properties.d.cts.map +1 -0
  156. package/dist/style/css-properties.d.mts +20 -0
  157. package/dist/style/css-properties.d.mts.map +1 -0
  158. package/dist/style/define-css-properties.cjs +25 -0
  159. package/dist/style/define-css-properties.cjs.map +1 -0
  160. package/dist/style/define-css-properties.d.cts +24 -0
  161. package/dist/style/define-css-properties.d.cts.map +1 -0
  162. package/dist/style/define-css-properties.d.mts +24 -0
  163. package/dist/style/define-css-properties.d.mts.map +1 -0
  164. package/dist/style/define-css-properties.mjs +24 -0
  165. package/dist/style/define-css-properties.mjs.map +1 -0
  166. package/dist/style/get-css-variable-value.cjs +11 -0
  167. package/dist/style/get-css-variable-value.cjs.map +1 -0
  168. package/dist/style/get-css-variable-value.d.cts +22 -0
  169. package/dist/style/get-css-variable-value.d.cts.map +1 -0
  170. package/dist/style/get-css-variable-value.d.mts +22 -0
  171. package/dist/style/get-css-variable-value.d.mts.map +1 -0
  172. package/dist/style/get-css-variable-value.mjs +10 -0
  173. package/dist/style/get-css-variable-value.mjs.map +1 -0
  174. package/dist/style/just-style.d.cts +44 -0
  175. package/dist/style/just-style.d.cts.map +1 -0
  176. package/dist/style/just-style.d.mts +44 -0
  177. package/dist/style/just-style.d.mts.map +1 -0
  178. package/dist/style/resolve-style.cjs +14 -0
  179. package/dist/style/resolve-style.cjs.map +1 -0
  180. package/dist/style/resolve-style.d.cts +11 -0
  181. package/dist/style/resolve-style.d.cts.map +1 -0
  182. package/dist/style/resolve-style.d.mts +11 -0
  183. package/dist/style/resolve-style.d.mts.map +1 -0
  184. package/dist/style/resolve-style.mjs +13 -0
  185. package/dist/style/resolve-style.mjs.map +1 -0
  186. package/dist/style/style-props.d.cts +13 -0
  187. package/dist/style/style-props.d.cts.map +1 -0
  188. package/dist/style/style-props.d.mts +13 -0
  189. package/dist/style/style-props.d.mts.map +1 -0
  190. package/dist/style/to-dom-style.cjs +33 -0
  191. package/dist/style/to-dom-style.cjs.map +1 -0
  192. package/dist/style/to-dom-style.d.cts +29 -0
  193. package/dist/style/to-dom-style.d.cts.map +1 -0
  194. package/dist/style/to-dom-style.d.mts +29 -0
  195. package/dist/style/to-dom-style.d.mts.map +1 -0
  196. package/dist/style/to-dom-style.mjs +32 -0
  197. package/dist/style/to-dom-style.mjs.map +1 -0
  198. package/dist/testing/theme/dummy-theme-store.cjs +11 -0
  199. package/dist/testing/theme/dummy-theme-store.cjs.map +1 -0
  200. package/dist/testing/theme/dummy-theme-store.mjs +10 -0
  201. package/dist/testing/theme/dummy-theme-store.mjs.map +1 -0
  202. package/dist/theme/_utils/get-theme-from-stores.cjs +24 -0
  203. package/dist/theme/_utils/get-theme-from-stores.cjs.map +1 -0
  204. package/dist/theme/_utils/get-theme-from-stores.mjs +23 -0
  205. package/dist/theme/_utils/get-theme-from-stores.mjs.map +1 -0
  206. package/dist/theme/_utils/observe-theme-from-stores.cjs +39 -0
  207. package/dist/theme/_utils/observe-theme-from-stores.cjs.map +1 -0
  208. package/dist/theme/_utils/observe-theme-from-stores.mjs +39 -0
  209. package/dist/theme/_utils/observe-theme-from-stores.mjs.map +1 -0
  210. package/dist/theme/_utils/parse-stored-theme.cjs +22 -0
  211. package/dist/theme/_utils/parse-stored-theme.cjs.map +1 -0
  212. package/dist/theme/_utils/parse-stored-theme.mjs +22 -0
  213. package/dist/theme/_utils/parse-stored-theme.mjs.map +1 -0
  214. package/dist/theme/_utils/set-theme-to-stores.cjs +16 -0
  215. package/dist/theme/_utils/set-theme-to-stores.cjs.map +1 -0
  216. package/dist/theme/_utils/set-theme-to-stores.mjs +15 -0
  217. package/dist/theme/_utils/set-theme-to-stores.mjs.map +1 -0
  218. package/dist/theme/class-name/apply-theme-to-class-name.cjs +23 -0
  219. package/dist/theme/class-name/apply-theme-to-class-name.cjs.map +1 -0
  220. package/dist/theme/class-name/apply-theme-to-class-name.mjs +22 -0
  221. package/dist/theme/class-name/apply-theme-to-class-name.mjs.map +1 -0
  222. package/dist/theme/class-name/resolve-theme-from-class-name.cjs +23 -0
  223. package/dist/theme/class-name/resolve-theme-from-class-name.cjs.map +1 -0
  224. package/dist/theme/class-name/resolve-theme-from-class-name.mjs +22 -0
  225. package/dist/theme/class-name/resolve-theme-from-class-name.mjs.map +1 -0
  226. package/dist/theme/compose-theme-stores.cjs +74 -0
  227. package/dist/theme/compose-theme-stores.cjs.map +1 -0
  228. package/dist/theme/compose-theme-stores.d.cts +33 -0
  229. package/dist/theme/compose-theme-stores.d.cts.map +1 -0
  230. package/dist/theme/compose-theme-stores.d.mts +33 -0
  231. package/dist/theme/compose-theme-stores.d.mts.map +1 -0
  232. package/dist/theme/compose-theme-stores.mjs +74 -0
  233. package/dist/theme/compose-theme-stores.mjs.map +1 -0
  234. package/dist/theme/data-attribute/apply-theme-to-data-attribute.cjs +23 -0
  235. package/dist/theme/data-attribute/apply-theme-to-data-attribute.cjs.map +1 -0
  236. package/dist/theme/data-attribute/apply-theme-to-data-attribute.mjs +22 -0
  237. package/dist/theme/data-attribute/apply-theme-to-data-attribute.mjs.map +1 -0
  238. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.cjs +23 -0
  239. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.cjs.map +1 -0
  240. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.mjs +22 -0
  241. package/dist/theme/data-attribute/resolve-theme-from-data-attribute.mjs.map +1 -0
  242. package/dist/theme/theme-entry.cjs +13 -0
  243. package/dist/theme/theme-entry.cjs.map +1 -0
  244. package/dist/theme/theme-entry.d.cts +9 -0
  245. package/dist/theme/theme-entry.d.cts.map +1 -0
  246. package/dist/theme/theme-entry.d.mts +9 -0
  247. package/dist/theme/theme-entry.d.mts.map +1 -0
  248. package/dist/theme/theme-entry.mjs +12 -0
  249. package/dist/theme/theme-entry.mjs.map +1 -0
  250. package/dist/theme/theme-entry.types.d.cts +16 -0
  251. package/dist/theme/theme-entry.types.d.cts.map +1 -0
  252. package/dist/theme/theme-entry.types.d.mts +16 -0
  253. package/dist/theme/theme-entry.types.d.mts.map +1 -0
  254. package/dist/theme/theme-map.types.d.cts +10 -0
  255. package/dist/theme/theme-map.types.d.cts.map +1 -0
  256. package/dist/theme/theme-map.types.d.mts +10 -0
  257. package/dist/theme/theme-map.types.d.mts.map +1 -0
  258. package/dist/theme/theme-store/async-theme-store.types.d.cts +25 -0
  259. package/dist/theme/theme-store/async-theme-store.types.d.cts.map +1 -0
  260. package/dist/theme/theme-store/async-theme-store.types.d.mts +25 -0
  261. package/dist/theme/theme-store/async-theme-store.types.d.mts.map +1 -0
  262. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs +53 -0
  263. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs.map +1 -0
  264. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.cts +28 -0
  265. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.cts.map +1 -0
  266. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.mts +28 -0
  267. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.mts.map +1 -0
  268. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs +53 -0
  269. package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs.map +1 -0
  270. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.cjs +121 -0
  271. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.cjs.map +1 -0
  272. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.cts +65 -0
  273. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.cts.map +1 -0
  274. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.mts +65 -0
  275. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.mts.map +1 -0
  276. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.mjs +120 -0
  277. package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.mjs.map +1 -0
  278. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs +51 -0
  279. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs.map +1 -0
  280. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.cts +30 -0
  281. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.cts.map +1 -0
  282. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.mts +30 -0
  283. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.mts.map +1 -0
  284. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs +51 -0
  285. package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs.map +1 -0
  286. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.cjs +54 -0
  287. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.cjs.map +1 -0
  288. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.cts +31 -0
  289. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.cts.map +1 -0
  290. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.mts +31 -0
  291. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.mts.map +1 -0
  292. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.mjs +54 -0
  293. package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.mjs.map +1 -0
  294. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.cjs +67 -0
  295. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.cjs.map +1 -0
  296. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.cts +34 -0
  297. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.cts.map +1 -0
  298. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.mts +34 -0
  299. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.mts.map +1 -0
  300. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs +67 -0
  301. package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs.map +1 -0
  302. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.cjs +39 -0
  303. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.cjs.map +1 -0
  304. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.cts +32 -0
  305. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.cts.map +1 -0
  306. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.mts +32 -0
  307. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.mts.map +1 -0
  308. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs +39 -0
  309. package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs.map +1 -0
  310. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.cjs +67 -0
  311. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.cjs.map +1 -0
  312. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.cts +34 -0
  313. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.cts.map +1 -0
  314. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.mts +34 -0
  315. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.mts.map +1 -0
  316. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs +67 -0
  317. package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs.map +1 -0
  318. package/dist/theme/theme-store/theme-store-factory.types.d.cts +10 -0
  319. package/dist/theme/theme-store/theme-store-factory.types.d.cts.map +1 -0
  320. package/dist/theme/theme-store/theme-store-factory.types.d.mts +10 -0
  321. package/dist/theme/theme-store/theme-store-factory.types.d.mts.map +1 -0
  322. package/dist/theme/theme-store/theme-store.types.d.cts +33 -0
  323. package/dist/theme/theme-store/theme-store.types.d.cts.map +1 -0
  324. package/dist/theme/theme-store/theme-store.types.d.mts +33 -0
  325. package/dist/theme/theme-store/theme-store.types.d.mts.map +1 -0
  326. package/dist/theme.cjs +20 -0
  327. package/dist/theme.d.cts +15 -0
  328. package/dist/theme.d.mts +15 -0
  329. package/dist/theme.mjs +11 -0
  330. package/dist/units/get-rem-to-px-scale.cjs +30 -0
  331. package/dist/units/get-rem-to-px-scale.cjs.map +1 -0
  332. package/dist/units/get-rem-to-px-scale.d.cts +21 -0
  333. package/dist/units/get-rem-to-px-scale.d.cts.map +1 -0
  334. package/dist/units/get-rem-to-px-scale.d.mts +21 -0
  335. package/dist/units/get-rem-to-px-scale.d.mts.map +1 -0
  336. package/dist/units/get-rem-to-px-scale.mjs +29 -0
  337. package/dist/units/get-rem-to-px-scale.mjs.map +1 -0
  338. package/dist/units/px-2-num.cjs +23 -0
  339. package/dist/units/px-2-num.cjs.map +1 -0
  340. package/dist/units/px-2-num.d.cts +19 -0
  341. package/dist/units/px-2-num.d.cts.map +1 -0
  342. package/dist/units/px-2-num.d.mts +19 -0
  343. package/dist/units/px-2-num.d.mts.map +1 -0
  344. package/dist/units/px-2-num.mjs +22 -0
  345. package/dist/units/px-2-num.mjs.map +1 -0
  346. package/dist/units/px-2-rem.cjs +31 -0
  347. package/dist/units/px-2-rem.cjs.map +1 -0
  348. package/dist/units/px-2-rem.d.cts +25 -0
  349. package/dist/units/px-2-rem.d.cts.map +1 -0
  350. package/dist/units/px-2-rem.d.mts +25 -0
  351. package/dist/units/px-2-rem.d.mts.map +1 -0
  352. package/dist/units/px-2-rem.mjs +30 -0
  353. package/dist/units/px-2-rem.mjs.map +1 -0
  354. package/dist/units/rem-2-px.cjs +31 -0
  355. package/dist/units/rem-2-px.cjs.map +1 -0
  356. package/dist/units/rem-2-px.d.cts +25 -0
  357. package/dist/units/rem-2-px.d.cts.map +1 -0
  358. package/dist/units/rem-2-px.d.mts +25 -0
  359. package/dist/units/rem-2-px.d.mts.map +1 -0
  360. package/dist/units/rem-2-px.mjs +30 -0
  361. package/dist/units/rem-2-px.mjs.map +1 -0
  362. package/dist/utils/append-id.cjs +16 -0
  363. package/dist/utils/append-id.cjs.map +1 -0
  364. package/dist/utils/append-id.d.cts +12 -0
  365. package/dist/utils/append-id.d.cts.map +1 -0
  366. package/dist/utils/append-id.d.mts +12 -0
  367. package/dist/utils/append-id.d.mts.map +1 -0
  368. package/dist/utils/append-id.mjs +15 -0
  369. package/dist/utils/append-id.mjs.map +1 -0
  370. package/package.json +120 -0
  371. package/readme.md +15 -0
  372. package/src/_internal/utils/try-parse-json.ts +8 -0
  373. package/src/attributes/data-attribute.ts +49 -0
  374. package/src/attributes/get-attribute.ts +20 -0
  375. package/src/attributes/get-data-attribute.ts +15 -0
  376. package/src/attributes/observe-attribute.ts +37 -0
  377. package/src/attributes/observe-data-attribute.ts +29 -0
  378. package/src/children/just-children-fn-props.editor.default.tsx +29 -0
  379. package/src/children/just-children-props.editor.default.tsx +17 -0
  380. package/src/children/just-children.editor.default.tsx +11 -0
  381. package/src/children/just-children.ts +37 -0
  382. package/src/children/resolve-children.ts +16 -0
  383. package/src/class-name/class-name-props.editor.tsx +13 -0
  384. package/src/class-name/class-name-props.ts +7 -0
  385. package/src/class-name/clsx.ts +3 -0
  386. package/src/class-name/just-class-name-props.editor.default.tsx +23 -0
  387. package/src/class-name/just-class-name-resolver-state.editor.default.tsx +18 -0
  388. package/src/class-name/just-class-name.editor.default-class-name.tsx +28 -0
  389. package/src/class-name/just-class-name.editor.default.tsx +14 -0
  390. package/src/class-name/just-class-name.editor.type-param.tsx +25 -0
  391. package/src/class-name/just-class-name.ts +36 -0
  392. package/src/class-name/resolve-class-name.ts +12 -0
  393. package/src/color-scheme/get-prefers-color-scheme.ts +17 -0
  394. package/src/color-scheme/observe-prefers-color-scheme.ts +24 -0
  395. package/src/index.ts +25 -0
  396. package/src/react/hooks/use-attribute.ts +59 -0
  397. package/src/react/hooks/use-prefers-color-scheme.ts +42 -0
  398. package/src/react/hooks/use-theme-by-class-name.ts +69 -0
  399. package/src/react/hooks/use-theme-by-data-attribute.ts +84 -0
  400. package/src/react/hooks/use-theme-by-local-storage.ts +68 -0
  401. package/src/react/hooks/use-theme-stores.ts +83 -0
  402. package/src/react/theme/create-theme-hook.ts +197 -0
  403. package/src/react.ts +7 -0
  404. package/src/style/css-properties.ts +20 -0
  405. package/src/style/define-css-properties.ts +23 -0
  406. package/src/style/get-css-variable-value.ts +32 -0
  407. package/src/style/just-style-props.editor.default.tsx +17 -0
  408. package/src/style/just-style-resolver-state.editor.default.tsx +22 -0
  409. package/src/style/just-style.editor.default.tsx +17 -0
  410. package/src/style/just-style.editor.type-param.tsx +31 -0
  411. package/src/style/just-style.ts +60 -0
  412. package/src/style/resolve-style.ts +23 -0
  413. package/src/style/style-props.editor.tsx +13 -0
  414. package/src/style/style-props.ts +8 -0
  415. package/src/style/to-dom-style.ts +36 -0
  416. package/src/testing/button.theme.ts +21 -0
  417. package/src/testing/button.tsx +11 -0
  418. package/src/testing/log-panel.tsx +14 -0
  419. package/src/testing/theme/dummy-theme-store.ts +7 -0
  420. package/src/testing/theme/theme-result-card.tsx +43 -0
  421. package/src/testing/theme/theme-store-demo.tsx +87 -0
  422. package/src/theme/_utils/get-theme-from-stores.ts +34 -0
  423. package/src/theme/_utils/observe-theme-from-stores.ts +57 -0
  424. package/src/theme/_utils/parse-stored-theme.ts +21 -0
  425. package/src/theme/_utils/set-theme-to-stores.ts +23 -0
  426. package/src/theme/class-name/apply-theme-to-class-name.ts +26 -0
  427. package/src/theme/class-name/resolve-theme-from-class-name.ts +22 -0
  428. package/src/theme/compose-theme-stores.ts +139 -0
  429. package/src/theme/data-attribute/apply-theme-to-data-attribute.ts +27 -0
  430. package/src/theme/data-attribute/resolve-theme-from-data-attribute.ts +23 -0
  431. package/src/theme/theme-entry.ts +10 -0
  432. package/src/theme/theme-entry.types.ts +11 -0
  433. package/src/theme/theme-map.types.ts +6 -0
  434. package/src/theme/theme-store/async-theme-store.types.ts +24 -0
  435. package/src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts +62 -0
  436. package/src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts +174 -0
  437. package/src/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.ts +60 -0
  438. package/src/theme/theme-store/in-memory-theme-store/in-memory-theme-store.ts +54 -0
  439. package/src/theme/theme-store/local-storage-theme-store/local-storage-theme-store.ts +83 -0
  440. package/src/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.ts +43 -0
  441. package/src/theme/theme-store/session-storage-theme-store/session-storage-theme-store.ts +83 -0
  442. package/src/theme/theme-store/theme-store-factory.types.ts +9 -0
  443. package/src/theme/theme-store/theme-store.types.ts +30 -0
  444. package/src/theme.ts +14 -0
  445. package/src/units/get-rem-to-px-scale.ts +27 -0
  446. package/src/units/px-2-num.ts +17 -0
  447. package/src/units/px-2-rem.ts +30 -0
  448. package/src/units/rem-2-px.ts +30 -0
  449. package/src/utils/append-id.ts +10 -0
@@ -0,0 +1,28 @@
1
+ import type { JustClassNameFnProps } from '@just-web/toolkits'
2
+ import { clsx } from '@just-web/toolkits'
3
+
4
+ function textTheme(renderProps?: JustClassNameFnProps) {
5
+ return {
6
+ ...renderProps,
7
+ className: clsx(renderProps?.className, 'text-black dark:text-white')
8
+ }
9
+ }
10
+
11
+ function hoverTheme(renderProps?: JustClassNameFnProps) {
12
+ return {
13
+ ...renderProps,
14
+ className: clsx(
15
+ renderProps?.className,
16
+ 'rounded outline-2 hover:outline-blue-300 dark:hover:outline-blue-700'
17
+ )
18
+ }
19
+ }
20
+
21
+ export default () => {
22
+ const props = hoverTheme(textTheme())
23
+ return (
24
+ <button type="button" {...props}>
25
+ Hover me
26
+ </button>
27
+ )
28
+ }
@@ -0,0 +1,14 @@
1
+ import type { JustClassName } from '@just-web/toolkits'
2
+ import { clsx } from '@just-web/toolkits'
3
+ import { StoryCard } from '@repobuddy/storybook'
4
+
5
+ const functionClassName: JustClassName<{ isSelected?: boolean | undefined }> = (renderProps) =>
6
+ clsx(renderProps.className, renderProps.isSelected && 'bg-blue-400')
7
+
8
+ export default () => {
9
+ return (
10
+ <StoryCard appearance="output">
11
+ <div>Result: {functionClassName({ className: 'base', isSelected: true })}</div>
12
+ </StoryCard>
13
+ )
14
+ }
@@ -0,0 +1,25 @@
1
+ import type { JustClassName } from '@just-web/toolkits'
2
+ import { clsx } from '@just-web/toolkits'
3
+ import { StoryCard } from '@repobuddy/storybook'
4
+
5
+ interface ButtonRenderProps {
6
+ isDisabled?: boolean | undefined
7
+ isPressed?: boolean | undefined
8
+ }
9
+
10
+ // With type param: function receives typed render props (ButtonRenderProps & { className?: string })
11
+ const classNameWhenDisabled: JustClassName<ButtonRenderProps> = (renderProps) =>
12
+ clsx(renderProps.className, renderProps.isDisabled && 'opacity-50 cursor-not-allowed')
13
+
14
+ const classNameWhenActive: JustClassName<ButtonRenderProps> = (renderProps) =>
15
+ clsx(renderProps.className, renderProps.isPressed && 'ring-2 ring-blue-500')
16
+
17
+ export default () => {
18
+ const renderProps: ButtonRenderProps = { isDisabled: true, isPressed: true }
19
+ return (
20
+ <StoryCard appearance="output">
21
+ <div>without className: {classNameWhenDisabled(renderProps)}</div>
22
+ <div>with className: {classNameWhenActive({ ...renderProps, className: 'btn' })}</div>
23
+ </StoryCard>
24
+ )
25
+ }
@@ -0,0 +1,36 @@
1
+ import type { AnyRecord } from 'type-plus'
2
+
3
+ /**
4
+ * Props interface for components that accept a render-props-aware `className`.
5
+ *
6
+ * Use this when defining component props that support the same `className` contract as {@link JustClassName}:
7
+ * a static string, a resolver function that receives render props (including existing `className`), or `undefined`.
8
+ *
9
+ * @typeParam RenderProps - Record type for render props. When `className` is a function, it receives `RenderProps` merged with `{ className?: string }`.
10
+ */
11
+ export interface JustClassNameProps<RenderProps extends AnyRecord = AnyRecord> {
12
+ className?: JustClassName<RenderProps> | undefined
13
+ }
14
+
15
+ /**
16
+ * A `className` type that can be static or computed from render props.
17
+ *
18
+ * - `string`: The value is appended to the existing `className` in render props.
19
+ * - `undefined`: Resets the `className` to `undefined`, removing existing `className`.
20
+ * - `function`: Process the render props and return the desired `className`.
21
+ *
22
+ * @typeParam RenderProps - Record type for render props. Resolvers receive `RenderProps` merged with `{ className?: string }`.
23
+ */
24
+ export type JustClassName<RenderProps extends AnyRecord = AnyRecord> =
25
+ | ((renderProps: JustClassNameFnProps<RenderProps>) => string | undefined)
26
+ | string
27
+ | undefined
28
+
29
+ /**
30
+ * The props type for `JustClassName` resolver functions.
31
+ *
32
+ * @typeParam RenderProps - Record type for render props.
33
+ */
34
+ export type JustClassNameFnProps<RenderProps extends AnyRecord = AnyRecord> = RenderProps & {
35
+ className?: string | undefined
36
+ }
@@ -0,0 +1,12 @@
1
+ import type { AnyRecord } from 'type-plus'
2
+ import { clsx } from './clsx.ts'
3
+ import type { JustClassName, JustClassNameFnProps } from './just-class-name.ts'
4
+
5
+ export function resolveClassName<RenderProps extends AnyRecord = AnyRecord>(
6
+ renderProps: JustClassNameFnProps<RenderProps>,
7
+ className?: JustClassName<RenderProps>
8
+ ) {
9
+ return typeof className === 'function'
10
+ ? className(renderProps)
11
+ : clsx(renderProps.className, className)
12
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Gets the current preferred color scheme.
3
+ * It can only be 'light' or 'dark'.
4
+ *
5
+ * Even if the browser preference is 'auto'/'device', it will return 'light' or 'dark'.
6
+ *
7
+ * When `matchMedia` is unavailable (e.g. SSR), returns `defaultColorScheme`.
8
+ *
9
+ * @param defaultColorScheme - Fallback when `matchMedia` is unavailable (default: `'light'`)
10
+ * @returns 'light' or 'dark'
11
+ */
12
+ export function getPrefersColorScheme(
13
+ defaultColorScheme: 'light' | 'dark' = 'light'
14
+ ): 'light' | 'dark' {
15
+ if (typeof matchMedia === 'undefined') return defaultColorScheme
16
+ return matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'
17
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Observes system color scheme preference changes and calls handlers when they occur.
3
+ *
4
+ * @param handler - A function that is called when the color scheme preference changes
5
+ * @returns A cleanup function that removes all event listeners
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * // Observe light/dark mode changes
10
+ * const cleanup = observePrefersColorScheme((value) => console.log('Color scheme changed to:', value))
11
+ *
12
+ * // Later, to stop observing:
13
+ * cleanup()
14
+ * ```
15
+ */
16
+ export function observePrefersColorScheme(handler: (value: 'light' | 'dark') => void) {
17
+ const m = globalThis.matchMedia('(prefers-color-scheme: light)')
18
+ const listener = (event: MediaQueryListEvent) => {
19
+ handler(event.matches ? 'light' : 'dark')
20
+ }
21
+
22
+ m.addEventListener('change', listener)
23
+ return () => m.removeEventListener('change', listener)
24
+ }
package/src/index.ts ADDED
@@ -0,0 +1,25 @@
1
+ export * from './attributes/data-attribute.ts'
2
+ export * from './attributes/get-attribute.ts'
3
+ export * from './attributes/get-data-attribute.ts'
4
+ export * from './attributes/observe-attribute.ts'
5
+ export * from './attributes/observe-data-attribute.ts'
6
+ export * from './children/just-children.ts'
7
+ export * from './children/resolve-children.ts'
8
+ export * from './class-name/class-name-props.ts'
9
+ export * from './class-name/clsx.ts'
10
+ export * from './class-name/just-class-name.ts'
11
+ export * from './class-name/resolve-class-name.ts'
12
+ export * from './color-scheme/get-prefers-color-scheme.ts'
13
+ export * from './color-scheme/observe-prefers-color-scheme.ts'
14
+ export * from './style/css-properties.ts'
15
+ export * from './style/define-css-properties.ts'
16
+ export * from './style/get-css-variable-value.ts'
17
+ export * from './style/just-style.ts'
18
+ export * from './style/resolve-style.ts'
19
+ export * from './style/style-props.ts'
20
+ export * from './style/to-dom-style.ts'
21
+ export * from './units/get-rem-to-px-scale.ts'
22
+ export * from './units/px-2-num.ts'
23
+ export * from './units/px-2-rem.ts'
24
+ export * from './units/rem-2-px.ts'
25
+ export * from './utils/append-id.ts'
@@ -0,0 +1,59 @@
1
+ import { useCallback, useEffect, useState } from 'react'
2
+ import { observeAttributes } from '../../attributes/observe-attribute.ts'
3
+
4
+ /**
5
+ * React hook that returns the current value of an attribute on a target element
6
+ * and a setter to update it. Stays in sync when the attribute changes (e.g. from elsewhere).
7
+ *
8
+ * @param attributeName - The attribute to observe (e.g. `'class'`, `'data-theme'`).
9
+ * @param element - The element to observe. Defaults to `document.documentElement` when omitted.
10
+ * @returns Tuple of [value, setValue]. Pass null to setValue to remove the attribute.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * const [className, setClassName] = useAttribute('class')
15
+ * const [theme, setTheme] = useAttribute('data-theme', myElement)
16
+ * setTheme('dark')
17
+ * setClassName(null) // removes class attribute
18
+ * ```
19
+ */
20
+ export function useAttribute(
21
+ attributeName: string,
22
+ element: Element | undefined = typeof document !== 'undefined'
23
+ ? document.documentElement
24
+ : undefined
25
+ ): [string | null, (value: string | null) => void] {
26
+ const [value, setValueState] = useState<string | null>(
27
+ () => element?.getAttribute(attributeName) ?? null
28
+ )
29
+
30
+ useEffect(() => {
31
+ if (!element) return
32
+
33
+ setValueState(element.getAttribute(attributeName))
34
+
35
+ const observer = observeAttributes(
36
+ {
37
+ [attributeName]: (next) => {
38
+ setValueState(next)
39
+ }
40
+ },
41
+ element
42
+ )
43
+ return () => observer.disconnect()
44
+ }, [element, attributeName])
45
+
46
+ const setValue = useCallback(
47
+ (next: string | null) => {
48
+ if (!element) return
49
+ if (next === null) {
50
+ element.removeAttribute(attributeName)
51
+ } else {
52
+ element.setAttribute(attributeName, next)
53
+ }
54
+ },
55
+ [element, attributeName]
56
+ )
57
+
58
+ return [value, setValue]
59
+ }
@@ -0,0 +1,42 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { getPrefersColorScheme } from '../../color-scheme/get-prefers-color-scheme.ts'
3
+ import { observePrefersColorScheme } from '../../color-scheme/observe-prefers-color-scheme.ts'
4
+
5
+ /**
6
+ * React hook that returns the current system color scheme preference and re-renders when it changes.
7
+ *
8
+ * Uses `prefers-color-scheme` media query. Returns `'light'` or `'dark'`; re-renders when the user
9
+ * changes their OS or browser light/dark setting.
10
+ *
11
+ * For SSR, uses `defaultColorScheme` when `matchMedia` is unavailable. On client, reads the real
12
+ * value immediately (no flicker); `useEffect` syncs and subscribes to changes.
13
+ *
14
+ * @param defaultColorScheme - Fallback when `matchMedia` is unavailable (default: `'light'`)
15
+ * @returns Current system color scheme: `'light'` or `'dark'`
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * const scheme = usePrefersColorScheme()
20
+ * return <div>System prefers: {scheme}</div>
21
+ * ```
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * const scheme = usePrefersColorScheme('dark')
26
+ * return <div>System prefers: {scheme}</div>
27
+ * ```
28
+ */
29
+ export function usePrefersColorScheme(
30
+ defaultColorScheme: 'light' | 'dark' = 'light'
31
+ ): 'light' | 'dark' {
32
+ const [scheme, setScheme] = useState<'light' | 'dark'>(() =>
33
+ getPrefersColorScheme(defaultColorScheme)
34
+ )
35
+
36
+ useEffect(() => {
37
+ setScheme(getPrefersColorScheme())
38
+ return observePrefersColorScheme(setScheme)
39
+ }, [])
40
+
41
+ return scheme
42
+ }
@@ -0,0 +1,69 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react'
2
+ import { observeThemeFromStores } from '../../theme/_utils/observe-theme-from-stores.ts'
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
+ import { themeEntry } from '../../theme/theme-entry.ts'
6
+ import type { ThemeMap } from '../../theme/theme-map.types.ts'
7
+ import { classNameThemeStore } from '../../theme/theme-store/class-name-theme-store/class-name-theme-store.ts'
8
+
9
+ /**
10
+ * React hook that returns the current theme (from element class) and a setter.
11
+ * Subscribes to class changes on the element so the returned theme stays in sync.
12
+ *
13
+ * @param themes - Record mapping theme keys to their class name values
14
+ * @param options.theme - Fallback theme key when no matching class is found
15
+ * @param options.element - Element to read/set theme on (defaults to document.documentElement)
16
+ * @returns Tuple of [currentTheme, setTheme]
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const themes = { light: 'theme-light', dark: 'theme-dark' }
21
+ * const [theme, setTheme] = useThemeByClassName(themes, { theme: 'light' })
22
+ *
23
+ * return (
24
+ * <>
25
+ * <span>Current: {theme}</span>
26
+ * <button onClick={() => setTheme('dark')}>Dark</button>
27
+ * <button onClick={() => setTheme('light')}>Light</button>
28
+ * </>
29
+ * )
30
+ * ```
31
+ */
32
+ export function useThemeByClassName<Themes extends ThemeMap>(
33
+ themes: Themes,
34
+ options?: {
35
+ defaultTheme?: keyof Themes | undefined
36
+ element?: Element | undefined
37
+ }
38
+ ): [keyof Themes | undefined, (theme: keyof Themes) => void] {
39
+ const element =
40
+ options?.element ?? (typeof document !== 'undefined' ? document.documentElement : undefined)
41
+ const defaultTheme = options?.defaultTheme
42
+
43
+ const store = useMemo(() => classNameThemeStore(themes, { element }), [element, themes])
44
+
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
+ })
52
+
53
+ useEffect(() => {
54
+ if (!element) return
55
+ const unobserve = observeThemeFromStores([store], defaultTheme, setThemeState)
56
+ return unobserve
57
+ }, [element, store, defaultTheme])
58
+
59
+ const setTheme = useCallback(
60
+ (themeKey: keyof Themes) => {
61
+ if (element) {
62
+ setThemeToStores([store], themeEntry(themes, themeKey))
63
+ }
64
+ },
65
+ [element, store, themes]
66
+ )
67
+
68
+ return [theme, setTheme]
69
+ }
@@ -0,0 +1,84 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react'
2
+ import { getDataAttribute } from '../../attributes/get-data-attribute.ts'
3
+ import { observeThemeFromStores } from '../../theme/_utils/observe-theme-from-stores.ts'
4
+ import { setThemeToStores } from '../../theme/_utils/set-theme-to-stores.ts'
5
+ import { resolveThemeFromDataAttribute } from '../../theme/data-attribute/resolve-theme-from-data-attribute.ts'
6
+ import { themeEntry } from '../../theme/theme-entry.ts'
7
+ import type { ThemeMap } from '../../theme/theme-map.types.ts'
8
+ import { dataAttributeThemeStore } from '../../theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.ts'
9
+
10
+ /**
11
+ * React hook that returns the current theme (from element data attribute) and a setter.
12
+ * Subscribes to data attribute changes on the element so the returned theme stays in sync.
13
+ *
14
+ * @param themes - Record mapping theme keys to their data attribute values
15
+ * @param options.attributeName - Data attribute name (e.g. `data-theme`)
16
+ * @param options.defaultTheme - Fallback theme key when no matching attribute value is found
17
+ * @param options.element - Element to read/set theme on (defaults to document.documentElement)
18
+ * @returns Tuple of [currentTheme, setTheme]
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * const themes = { light: 'theme-light', dark: 'theme-dark' }
23
+ * const [theme, setTheme] = useThemeByDataAttribute(themes, {
24
+ * attributeName: 'data-theme',
25
+ * defaultTheme: 'light'
26
+ * })
27
+ *
28
+ * return (
29
+ * <>
30
+ * <span>Current: {theme}</span>
31
+ * <button onClick={() => setTheme('dark')}>Dark</button>
32
+ * <button onClick={() => setTheme('light')}>Light</button>
33
+ * </>
34
+ * )
35
+ * ```
36
+ */
37
+ export function useThemeByDataAttribute<Themes extends ThemeMap>(
38
+ themes: Themes,
39
+ options: {
40
+ attributeName: `data-${string}`
41
+ defaultTheme?: keyof Themes | undefined
42
+ element?: Element | undefined
43
+ }
44
+ ): [keyof Themes | undefined, (theme: keyof Themes) => void] {
45
+ const element =
46
+ options.element ?? (typeof document !== 'undefined' ? document.documentElement : undefined)
47
+ const defaultTheme = options.defaultTheme
48
+ const attributeName = options.attributeName
49
+
50
+ const store = useMemo(
51
+ () =>
52
+ dataAttributeThemeStore(themes, {
53
+ attributeName,
54
+ element
55
+ }),
56
+ [element, themes, attributeName]
57
+ )
58
+
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
+ })
67
+
68
+ useEffect(() => {
69
+ if (!element) return
70
+ const unobserve = observeThemeFromStores([store], defaultTheme, setThemeState)
71
+ return unobserve
72
+ }, [element, store, defaultTheme])
73
+
74
+ const setTheme = useCallback(
75
+ (themeKey: keyof Themes) => {
76
+ if (element) {
77
+ setThemeToStores([store], themeEntry(themes, themeKey))
78
+ }
79
+ },
80
+ [element, store, themes]
81
+ )
82
+
83
+ return [theme, setTheme]
84
+ }
@@ -0,0 +1,68 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react'
2
+ import { observeThemeFromStores } from '../../theme/_utils/observe-theme-from-stores.ts'
3
+ import { parseStoredTheme } from '../../theme/_utils/parse-stored-theme.ts'
4
+ import { setThemeToStores } from '../../theme/_utils/set-theme-to-stores.ts'
5
+ import { themeEntry } from '../../theme/theme-entry.ts'
6
+ import type { ThemeMap } from '../../theme/theme-map.types.ts'
7
+ import { localStorageThemeStore } from '../../theme/theme-store/local-storage-theme-store/local-storage-theme-store.ts'
8
+
9
+ /**
10
+ * React hook that returns the current theme (from localStorage) and a setter.
11
+ * Subscribes to storage changes so the returned theme stays in sync across tabs.
12
+ *
13
+ * @param themes - Record mapping theme keys to their values
14
+ * @param options.storageKey - localStorage key to persist the theme
15
+ * @param options.defaultTheme - Fallback theme key when no stored value is found
16
+ * @returns Tuple of [currentTheme, setTheme]
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const themes = { light: 'theme-light', dark: 'theme-dark' }
21
+ * const [theme, setTheme] = useThemeByLocalStorage(themes, {
22
+ * storageKey: 'app-theme',
23
+ * defaultTheme: 'light'
24
+ * })
25
+ *
26
+ * return (
27
+ * <>
28
+ * <span>Current: {theme}</span>
29
+ * <button onClick={() => setTheme('dark')}>Dark</button>
30
+ * <button onClick={() => setTheme('light')}>Light</button>
31
+ * </>
32
+ * )
33
+ * ```
34
+ */
35
+ export function useThemeByLocalStorage<Themes extends ThemeMap>(
36
+ themes: Themes,
37
+ options: {
38
+ storageKey: string
39
+ defaultTheme?: keyof Themes | undefined
40
+ }
41
+ ): [keyof Themes | undefined, (theme: keyof Themes) => void] {
42
+ const { storageKey, defaultTheme } = options
43
+
44
+ const store = useMemo(() => localStorageThemeStore(themes, { storageKey }), [themes, storageKey])
45
+
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
+ })
54
+
55
+ useEffect(() => {
56
+ const unobserve = observeThemeFromStores([store], defaultTheme, setThemeState)
57
+ return unobserve
58
+ }, [store, defaultTheme])
59
+
60
+ const setTheme = useCallback(
61
+ (themeKey: keyof Themes) => {
62
+ setThemeToStores([store], themeEntry(themes, themeKey))
63
+ },
64
+ [store, themes]
65
+ )
66
+
67
+ return [theme, setTheme]
68
+ }
@@ -0,0 +1,83 @@
1
+ import { useMemo } from 'react'
2
+ import type {
3
+ ComposeThemeStoreEntry,
4
+ ComposeThemeStoresOptions
5
+ } from '../../theme/compose-theme-stores.ts'
6
+ import type { ThemeMap } from '../../theme/theme-map.types.ts'
7
+ import type { ThemeStoreFactory } from '../../theme/theme-store/theme-store-factory.types.ts'
8
+ import { createThemeHook } from '../theme/create-theme-hook.ts'
9
+
10
+ type ThemeStoresTuple<
11
+ Themes extends ThemeMap,
12
+ A extends ThemeStoreFactory<Themes> = never,
13
+ B extends ThemeStoreFactory<Themes> = never,
14
+ C extends ThemeStoreFactory<Themes> = never,
15
+ D extends ThemeStoreFactory<Themes> = never,
16
+ E extends ThemeStoreFactory<Themes> = never,
17
+ F extends ThemeStoreFactory<Themes> = never,
18
+ G extends ThemeStoreFactory<Themes> = never,
19
+ H extends ThemeStoreFactory<Themes> = never
20
+ > = readonly [
21
+ store1: ComposeThemeStoreEntry<Themes, A>,
22
+ store2?: ComposeThemeStoreEntry<Themes, B>,
23
+ store3?: ComposeThemeStoreEntry<Themes, C>,
24
+ store4?: ComposeThemeStoreEntry<Themes, D>,
25
+ store5?: ComposeThemeStoreEntry<Themes, E>,
26
+ store6?: ComposeThemeStoreEntry<Themes, F>,
27
+ store7?: ComposeThemeStoreEntry<Themes, G>,
28
+ store8?: ComposeThemeStoreEntry<Themes, H>
29
+ ]
30
+
31
+ /**
32
+ * React hook that returns the current theme and a setter for composed theme stores.
33
+ * Delegates to createThemeHook internally.
34
+ *
35
+ * Accepts `stores` in two forms:
36
+ * - **Factory (recommended):** `() => [store1, store2, ...]` — run once on mount; no memoization needed.
37
+ * - **Array:** `[store1, store2, ...]` — must be memoized or ref-stable; recreating the array each render breaks subscriptions.
38
+ *
39
+ * @param themes - ThemeMap mapping theme keys to their values (e.g. CSS class names)
40
+ * @param stores - Array or factory returning 1–8 theme stores (see ComposeThemeStoreEntry)
41
+ * @param options.defaultTheme - Fallback theme key when stores return empty; also used for SSR
42
+ * @returns Tuple of [currentTheme, setTheme]
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * // Factory form — no memoization needed
47
+ * const [theme, setTheme] = useThemeStores(
48
+ * themes,
49
+ * () => [inMemoryThemeStore(themes)],
50
+ * { defaultTheme: 'light' }
51
+ * )
52
+ *
53
+ * // Array form — must be memoized
54
+ * const stores = useMemo(() => [localStorageStore], [])
55
+ * const [theme, setTheme] = useThemeStores(themes, stores, { defaultTheme: 'light' })
56
+ * setTheme('dark')
57
+ * ```
58
+ */
59
+ export function useThemeStores<
60
+ Themes extends ThemeMap,
61
+ A extends ThemeStoreFactory<Themes> = never,
62
+ B extends ThemeStoreFactory<Themes> = never,
63
+ C extends ThemeStoreFactory<Themes> = never,
64
+ D extends ThemeStoreFactory<Themes> = never,
65
+ E extends ThemeStoreFactory<Themes> = never,
66
+ F extends ThemeStoreFactory<Themes> = never,
67
+ G extends ThemeStoreFactory<Themes> = never,
68
+ H extends ThemeStoreFactory<Themes> = never
69
+ >(
70
+ themes: Themes,
71
+ stores:
72
+ | ThemeStoresTuple<Themes, A, B, C, D, E, F, G, H>
73
+ | (() => ThemeStoresTuple<Themes, A, B, C, D, E, F, G, H>),
74
+ options?: ComposeThemeStoresOptions<Themes>
75
+ ): [keyof Themes | undefined, (theme: keyof Themes) => void] {
76
+ const resolvedStores = useMemo(
77
+ () => (typeof stores === 'function' ? stores() : stores),
78
+ // Empty deps: factory runs once on mount; array form must be ref-stable (user memoizes)
79
+ []
80
+ )
81
+ const useTheme = createThemeHook<Themes, A, B, C, D, E, F, G, H>(themes, resolvedStores, options)
82
+ return useTheme(options?.defaultTheme)
83
+ }