@usels/core 0.0.1

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 (341) hide show
  1. package/README.md +21 -0
  2. package/dist/browser/useEventListener/index.d.mts +56 -0
  3. package/dist/browser/useEventListener/index.d.ts +56 -0
  4. package/dist/browser/useEventListener/index.js +112 -0
  5. package/dist/browser/useEventListener/index.js.map +1 -0
  6. package/dist/browser/useEventListener/index.mjs +88 -0
  7. package/dist/browser/useEventListener/index.mjs.map +1 -0
  8. package/dist/browser/useMediaQuery/demo.d.mts +5 -0
  9. package/dist/browser/useMediaQuery/demo.d.ts +5 -0
  10. package/dist/browser/useMediaQuery/demo.js +83 -0
  11. package/dist/browser/useMediaQuery/demo.js.map +1 -0
  12. package/dist/browser/useMediaQuery/demo.mjs +63 -0
  13. package/dist/browser/useMediaQuery/demo.mjs.map +1 -0
  14. package/dist/browser/useMediaQuery/index.d.mts +11 -0
  15. package/dist/browser/useMediaQuery/index.d.ts +11 -0
  16. package/dist/browser/useMediaQuery/index.js +89 -0
  17. package/dist/browser/useMediaQuery/index.js.map +1 -0
  18. package/dist/browser/useMediaQuery/index.mjs +64 -0
  19. package/dist/browser/useMediaQuery/index.mjs.map +1 -0
  20. package/dist/components/Auto/index.d.mts +33 -0
  21. package/dist/components/Auto/index.d.ts +33 -0
  22. package/dist/components/Auto/index.js +66 -0
  23. package/dist/components/Auto/index.js.map +1 -0
  24. package/dist/components/Auto/index.mjs +34 -0
  25. package/dist/components/Auto/index.mjs.map +1 -0
  26. package/dist/elements/useDocumentVisibility/demo.d.mts +5 -0
  27. package/dist/elements/useDocumentVisibility/demo.d.ts +5 -0
  28. package/dist/elements/useDocumentVisibility/demo.js +130 -0
  29. package/dist/elements/useDocumentVisibility/demo.js.map +1 -0
  30. package/dist/elements/useDocumentVisibility/demo.mjs +114 -0
  31. package/dist/elements/useDocumentVisibility/demo.mjs.map +1 -0
  32. package/dist/elements/useDocumentVisibility/index.d.mts +5 -0
  33. package/dist/elements/useDocumentVisibility/index.d.ts +5 -0
  34. package/dist/elements/useDocumentVisibility/index.js +45 -0
  35. package/dist/elements/useDocumentVisibility/index.js.map +1 -0
  36. package/dist/elements/useDocumentVisibility/index.mjs +21 -0
  37. package/dist/elements/useDocumentVisibility/index.mjs.map +1 -0
  38. package/dist/elements/useElementBounding/demo.d.mts +5 -0
  39. package/dist/elements/useElementBounding/demo.d.ts +5 -0
  40. package/dist/elements/useElementBounding/demo.js +87 -0
  41. package/dist/elements/useElementBounding/demo.js.map +1 -0
  42. package/dist/elements/useElementBounding/demo.mjs +67 -0
  43. package/dist/elements/useElementBounding/demo.mjs.map +1 -0
  44. package/dist/elements/useElementBounding/index.d.mts +46 -0
  45. package/dist/elements/useElementBounding/index.d.ts +46 -0
  46. package/dist/elements/useElementBounding/index.js +122 -0
  47. package/dist/elements/useElementBounding/index.js.map +1 -0
  48. package/dist/elements/useElementBounding/index.mjs +98 -0
  49. package/dist/elements/useElementBounding/index.mjs.map +1 -0
  50. package/dist/elements/useElementSize/demo.d.mts +5 -0
  51. package/dist/elements/useElementSize/demo.d.ts +5 -0
  52. package/dist/elements/useElementSize/demo.js +83 -0
  53. package/dist/elements/useElementSize/demo.js.map +1 -0
  54. package/dist/elements/useElementSize/demo.mjs +63 -0
  55. package/dist/elements/useElementSize/demo.mjs.map +1 -0
  56. package/dist/elements/useElementSize/index.d.mts +34 -0
  57. package/dist/elements/useElementSize/index.d.ts +34 -0
  58. package/dist/elements/useElementSize/index.js +85 -0
  59. package/dist/elements/useElementSize/index.js.map +1 -0
  60. package/dist/elements/useElementSize/index.mjs +61 -0
  61. package/dist/elements/useElementSize/index.mjs.map +1 -0
  62. package/dist/elements/useElementVisibility/demo.d.mts +5 -0
  63. package/dist/elements/useElementVisibility/demo.d.ts +5 -0
  64. package/dist/elements/useElementVisibility/demo.js +110 -0
  65. package/dist/elements/useElementVisibility/demo.js.map +1 -0
  66. package/dist/elements/useElementVisibility/demo.mjs +90 -0
  67. package/dist/elements/useElementVisibility/demo.mjs.map +1 -0
  68. package/dist/elements/useElementVisibility/index.d.mts +43 -0
  69. package/dist/elements/useElementVisibility/index.d.ts +43 -0
  70. package/dist/elements/useElementVisibility/index.js +58 -0
  71. package/dist/elements/useElementVisibility/index.js.map +1 -0
  72. package/dist/elements/useElementVisibility/index.mjs +34 -0
  73. package/dist/elements/useElementVisibility/index.mjs.map +1 -0
  74. package/dist/elements/useIntersectionObserver/demo.d.mts +5 -0
  75. package/dist/elements/useIntersectionObserver/demo.d.ts +5 -0
  76. package/dist/elements/useIntersectionObserver/demo.js +173 -0
  77. package/dist/elements/useIntersectionObserver/demo.js.map +1 -0
  78. package/dist/elements/useIntersectionObserver/demo.mjs +153 -0
  79. package/dist/elements/useIntersectionObserver/demo.mjs.map +1 -0
  80. package/dist/elements/useIntersectionObserver/index.d.mts +47 -0
  81. package/dist/elements/useIntersectionObserver/index.d.ts +47 -0
  82. package/dist/elements/useIntersectionObserver/index.js +111 -0
  83. package/dist/elements/useIntersectionObserver/index.js.map +1 -0
  84. package/dist/elements/useIntersectionObserver/index.mjs +87 -0
  85. package/dist/elements/useIntersectionObserver/index.mjs.map +1 -0
  86. package/dist/elements/useMouseInElement/demo.d.mts +5 -0
  87. package/dist/elements/useMouseInElement/demo.d.ts +5 -0
  88. package/dist/elements/useMouseInElement/demo.js +104 -0
  89. package/dist/elements/useMouseInElement/demo.js.map +1 -0
  90. package/dist/elements/useMouseInElement/demo.mjs +84 -0
  91. package/dist/elements/useMouseInElement/demo.mjs.map +1 -0
  92. package/dist/elements/useMouseInElement/index.d.mts +56 -0
  93. package/dist/elements/useMouseInElement/index.d.ts +56 -0
  94. package/dist/elements/useMouseInElement/index.js +148 -0
  95. package/dist/elements/useMouseInElement/index.js.map +1 -0
  96. package/dist/elements/useMouseInElement/index.mjs +124 -0
  97. package/dist/elements/useMouseInElement/index.mjs.map +1 -0
  98. package/dist/elements/useMutationObserver/demo.d.mts +5 -0
  99. package/dist/elements/useMutationObserver/demo.d.ts +5 -0
  100. package/dist/elements/useMutationObserver/demo.js +240 -0
  101. package/dist/elements/useMutationObserver/demo.js.map +1 -0
  102. package/dist/elements/useMutationObserver/demo.mjs +220 -0
  103. package/dist/elements/useMutationObserver/demo.mjs.map +1 -0
  104. package/dist/elements/useMutationObserver/index.d.mts +15 -0
  105. package/dist/elements/useMutationObserver/index.d.ts +15 -0
  106. package/dist/elements/useMutationObserver/index.js +69 -0
  107. package/dist/elements/useMutationObserver/index.js.map +1 -0
  108. package/dist/elements/useMutationObserver/index.mjs +45 -0
  109. package/dist/elements/useMutationObserver/index.mjs.map +1 -0
  110. package/dist/elements/useParentElement/demo.d.mts +5 -0
  111. package/dist/elements/useParentElement/demo.d.ts +5 -0
  112. package/dist/elements/useParentElement/demo.js +132 -0
  113. package/dist/elements/useParentElement/demo.js.map +1 -0
  114. package/dist/elements/useParentElement/demo.mjs +112 -0
  115. package/dist/elements/useParentElement/demo.mjs.map +1 -0
  116. package/dist/elements/useParentElement/index.d.mts +7 -0
  117. package/dist/elements/useParentElement/index.d.ts +7 -0
  118. package/dist/elements/useParentElement/index.js +47 -0
  119. package/dist/elements/useParentElement/index.js.map +1 -0
  120. package/dist/elements/useParentElement/index.mjs +23 -0
  121. package/dist/elements/useParentElement/index.mjs.map +1 -0
  122. package/dist/elements/useRef$/index.js +89 -0
  123. package/dist/elements/useRef$/index.js.map +1 -0
  124. package/dist/elements/useRef$/index.mjs +62 -0
  125. package/dist/elements/useRef$/index.mjs.map +1 -0
  126. package/dist/elements/useRef_/index.d.mts +60 -0
  127. package/dist/elements/useRef_/index.d.ts +60 -0
  128. package/dist/elements/useResizeObserver/demo.d.mts +5 -0
  129. package/dist/elements/useResizeObserver/demo.d.ts +5 -0
  130. package/dist/elements/useResizeObserver/demo.js +90 -0
  131. package/dist/elements/useResizeObserver/demo.js.map +1 -0
  132. package/dist/elements/useResizeObserver/demo.mjs +70 -0
  133. package/dist/elements/useResizeObserver/demo.mjs.map +1 -0
  134. package/dist/elements/useResizeObserver/index.d.mts +36 -0
  135. package/dist/elements/useResizeObserver/index.d.ts +36 -0
  136. package/dist/elements/useResizeObserver/index.js +74 -0
  137. package/dist/elements/useResizeObserver/index.js.map +1 -0
  138. package/dist/elements/useResizeObserver/index.mjs +49 -0
  139. package/dist/elements/useResizeObserver/index.mjs.map +1 -0
  140. package/dist/elements/useWindowFocus/demo.d.mts +5 -0
  141. package/dist/elements/useWindowFocus/demo.d.ts +5 -0
  142. package/dist/elements/useWindowFocus/demo.js +104 -0
  143. package/dist/elements/useWindowFocus/demo.js.map +1 -0
  144. package/dist/elements/useWindowFocus/demo.mjs +84 -0
  145. package/dist/elements/useWindowFocus/demo.mjs.map +1 -0
  146. package/dist/elements/useWindowFocus/index.d.mts +5 -0
  147. package/dist/elements/useWindowFocus/index.d.ts +5 -0
  148. package/dist/elements/useWindowFocus/index.js +42 -0
  149. package/dist/elements/useWindowFocus/index.js.map +1 -0
  150. package/dist/elements/useWindowFocus/index.mjs +18 -0
  151. package/dist/elements/useWindowFocus/index.mjs.map +1 -0
  152. package/dist/elements/useWindowSize/demo.d.mts +5 -0
  153. package/dist/elements/useWindowSize/demo.d.ts +5 -0
  154. package/dist/elements/useWindowSize/demo.js +79 -0
  155. package/dist/elements/useWindowSize/demo.js.map +1 -0
  156. package/dist/elements/useWindowSize/demo.mjs +59 -0
  157. package/dist/elements/useWindowSize/demo.mjs.map +1 -0
  158. package/dist/elements/useWindowSize/index.d.mts +17 -0
  159. package/dist/elements/useWindowSize/index.d.ts +17 -0
  160. package/dist/elements/useWindowSize/index.js +96 -0
  161. package/dist/elements/useWindowSize/index.js.map +1 -0
  162. package/dist/elements/useWindowSize/index.mjs +76 -0
  163. package/dist/elements/useWindowSize/index.mjs.map +1 -0
  164. package/dist/function/get/index.d.mts +45 -0
  165. package/dist/function/get/index.d.ts +45 -0
  166. package/dist/function/get/index.js +39 -0
  167. package/dist/function/get/index.js.map +1 -0
  168. package/dist/function/get/index.mjs +15 -0
  169. package/dist/function/get/index.mjs.map +1 -0
  170. package/dist/function/peek/index.d.mts +46 -0
  171. package/dist/function/peek/index.d.ts +46 -0
  172. package/dist/function/peek/index.js +39 -0
  173. package/dist/function/peek/index.js.map +1 -0
  174. package/dist/function/peek/index.mjs +15 -0
  175. package/dist/function/peek/index.mjs.map +1 -0
  176. package/dist/function/useMayObservableOptions/index.d.mts +59 -0
  177. package/dist/function/useMayObservableOptions/index.d.ts +59 -0
  178. package/dist/function/useMayObservableOptions/index.js +109 -0
  179. package/dist/function/useMayObservableOptions/index.js.map +1 -0
  180. package/dist/function/useMayObservableOptions/index.mjs +88 -0
  181. package/dist/function/useMayObservableOptions/index.mjs.map +1 -0
  182. package/dist/function/useSupported/index.d.mts +6 -0
  183. package/dist/function/useSupported/index.d.ts +6 -0
  184. package/dist/function/useSupported/index.js +37 -0
  185. package/dist/function/useSupported/index.js.map +1 -0
  186. package/dist/function/useSupported/index.mjs +13 -0
  187. package/dist/function/useSupported/index.mjs.map +1 -0
  188. package/dist/function/useWhenMounted/index.d.mts +6 -0
  189. package/dist/function/useWhenMounted/index.d.ts +6 -0
  190. package/dist/function/useWhenMounted/index.js +37 -0
  191. package/dist/function/useWhenMounted/index.js.map +1 -0
  192. package/dist/function/useWhenMounted/index.mjs +13 -0
  193. package/dist/function/useWhenMounted/index.mjs.map +1 -0
  194. package/dist/index.d.mts +24 -0
  195. package/dist/index.d.ts +24 -0
  196. package/dist/index.js +63 -0
  197. package/dist/index.js.map +1 -0
  198. package/dist/index.mjs +22 -0
  199. package/dist/index.mjs.map +1 -0
  200. package/dist/sensors/useScroll/demo.d.mts +5 -0
  201. package/dist/sensors/useScroll/demo.d.ts +5 -0
  202. package/dist/sensors/useScroll/demo.js +122 -0
  203. package/dist/sensors/useScroll/demo.js.map +1 -0
  204. package/dist/sensors/useScroll/demo.mjs +102 -0
  205. package/dist/sensors/useScroll/demo.mjs.map +1 -0
  206. package/dist/sensors/useScroll/index.d.mts +42 -0
  207. package/dist/sensors/useScroll/index.d.ts +42 -0
  208. package/dist/sensors/useScroll/index.js +149 -0
  209. package/dist/sensors/useScroll/index.js.map +1 -0
  210. package/dist/sensors/useScroll/index.mjs +125 -0
  211. package/dist/sensors/useScroll/index.mjs.map +1 -0
  212. package/dist/sensors/useWindowScroll/demo.d.mts +5 -0
  213. package/dist/sensors/useWindowScroll/demo.d.ts +5 -0
  214. package/dist/sensors/useWindowScroll/demo.js +85 -0
  215. package/dist/sensors/useWindowScroll/demo.js.map +1 -0
  216. package/dist/sensors/useWindowScroll/demo.mjs +65 -0
  217. package/dist/sensors/useWindowScroll/demo.mjs.map +1 -0
  218. package/dist/sensors/useWindowScroll/index.d.mts +9 -0
  219. package/dist/sensors/useWindowScroll/index.d.ts +9 -0
  220. package/dist/sensors/useWindowScroll/index.js +36 -0
  221. package/dist/sensors/useWindowScroll/index.js.map +1 -0
  222. package/dist/sensors/useWindowScroll/index.mjs +12 -0
  223. package/dist/sensors/useWindowScroll/index.mjs.map +1 -0
  224. package/dist/shared/configurable.d.mts +21 -0
  225. package/dist/shared/configurable.d.ts +21 -0
  226. package/dist/shared/configurable.js +39 -0
  227. package/dist/shared/configurable.js.map +1 -0
  228. package/dist/shared/configurable.mjs +12 -0
  229. package/dist/shared/configurable.mjs.map +1 -0
  230. package/dist/shared/index.d.mts +4 -0
  231. package/dist/shared/index.d.ts +4 -0
  232. package/dist/shared/index.js +31 -0
  233. package/dist/shared/index.js.map +1 -0
  234. package/dist/shared/index.mjs +7 -0
  235. package/dist/shared/index.mjs.map +1 -0
  236. package/dist/shared/normalizeTargets/index.d.mts +21 -0
  237. package/dist/shared/normalizeTargets/index.d.ts +21 -0
  238. package/dist/shared/normalizeTargets/index.js +36 -0
  239. package/dist/shared/normalizeTargets/index.js.map +1 -0
  240. package/dist/shared/normalizeTargets/index.mjs +12 -0
  241. package/dist/shared/normalizeTargets/index.mjs.map +1 -0
  242. package/dist/shared/utils.d.mts +15 -0
  243. package/dist/shared/utils.d.ts +15 -0
  244. package/dist/shared/utils.js +87 -0
  245. package/dist/shared/utils.js.map +1 -0
  246. package/dist/shared/utils.mjs +52 -0
  247. package/dist/shared/utils.mjs.map +1 -0
  248. package/dist/types.d.mts +52 -0
  249. package/dist/types.d.ts +52 -0
  250. package/dist/types.js +17 -0
  251. package/dist/types.js.map +1 -0
  252. package/dist/types.mjs +1 -0
  253. package/dist/types.mjs.map +1 -0
  254. package/package.json +54 -0
  255. package/src/browser/useEventListener/index.md +109 -0
  256. package/src/browser/useEventListener/index.spec.ts +611 -0
  257. package/src/browser/useEventListener/index.ts +242 -0
  258. package/src/browser/useMediaQuery/demo.tsx +63 -0
  259. package/src/browser/useMediaQuery/index.md +43 -0
  260. package/src/browser/useMediaQuery/index.spec.ts +267 -0
  261. package/src/browser/useMediaQuery/index.ts +96 -0
  262. package/src/components/Auto/index.tsx +65 -0
  263. package/src/elements/useDocumentVisibility/demo.tsx +111 -0
  264. package/src/elements/useDocumentVisibility/index.md +54 -0
  265. package/src/elements/useDocumentVisibility/index.spec.ts +114 -0
  266. package/src/elements/useDocumentVisibility/index.ts +26 -0
  267. package/src/elements/useElementBounding/demo.tsx +68 -0
  268. package/src/elements/useElementBounding/index.md +64 -0
  269. package/src/elements/useElementBounding/index.ts +159 -0
  270. package/src/elements/useElementSize/demo.tsx +53 -0
  271. package/src/elements/useElementSize/index.md +65 -0
  272. package/src/elements/useElementSize/index.spec.ts +295 -0
  273. package/src/elements/useElementSize/index.ts +100 -0
  274. package/src/elements/useElementVisibility/deep-observable-pattern.spec.ts +453 -0
  275. package/src/elements/useElementVisibility/demo.tsx +97 -0
  276. package/src/elements/useElementVisibility/index.md +98 -0
  277. package/src/elements/useElementVisibility/index.spec.ts +227 -0
  278. package/src/elements/useElementVisibility/index.ts +78 -0
  279. package/src/elements/useIntersectionObserver/demo.tsx +180 -0
  280. package/src/elements/useIntersectionObserver/index.md +99 -0
  281. package/src/elements/useIntersectionObserver/index.spec.ts +482 -0
  282. package/src/elements/useIntersectionObserver/index.ts +149 -0
  283. package/src/elements/useMouseInElement/demo.tsx +88 -0
  284. package/src/elements/useMouseInElement/index.md +76 -0
  285. package/src/elements/useMouseInElement/index.spec.ts +398 -0
  286. package/src/elements/useMouseInElement/index.ts +209 -0
  287. package/src/elements/useMutationObserver/demo.tsx +270 -0
  288. package/src/elements/useMutationObserver/index.md +99 -0
  289. package/src/elements/useMutationObserver/index.spec.ts +421 -0
  290. package/src/elements/useMutationObserver/index.ts +66 -0
  291. package/src/elements/useParentElement/demo.tsx +120 -0
  292. package/src/elements/useParentElement/index.md +67 -0
  293. package/src/elements/useParentElement/index.spec.ts +208 -0
  294. package/src/elements/useParentElement/index.ts +35 -0
  295. package/src/elements/useRef$/index.md +62 -0
  296. package/src/elements/useRef$/index.spec.ts +205 -0
  297. package/src/elements/useRef$/index.ts +137 -0
  298. package/src/elements/useRef$/useImperativeHandle.spec.ts +339 -0
  299. package/src/elements/useResizeObserver/demo.tsx +62 -0
  300. package/src/elements/useResizeObserver/index.md +51 -0
  301. package/src/elements/useResizeObserver/index.spec.ts +312 -0
  302. package/src/elements/useResizeObserver/index.ts +106 -0
  303. package/src/elements/useWindowFocus/demo.tsx +79 -0
  304. package/src/elements/useWindowFocus/index.md +38 -0
  305. package/src/elements/useWindowFocus/index.spec.ts +103 -0
  306. package/src/elements/useWindowFocus/index.ts +21 -0
  307. package/src/elements/useWindowSize/demo.tsx +51 -0
  308. package/src/elements/useWindowSize/index.md +55 -0
  309. package/src/elements/useWindowSize/index.spec.ts +310 -0
  310. package/src/elements/useWindowSize/index.ts +107 -0
  311. package/src/function/get/index.md +25 -0
  312. package/src/function/get/index.spec.ts +87 -0
  313. package/src/function/get/index.ts +70 -0
  314. package/src/function/peek/index.spec.ts +97 -0
  315. package/src/function/peek/index.ts +69 -0
  316. package/src/function/useMayObservableOptions/index.spec.ts +521 -0
  317. package/src/function/useMayObservableOptions/index.ts +173 -0
  318. package/src/function/useSupported/index.md +43 -0
  319. package/src/function/useSupported/index.spec.ts +116 -0
  320. package/src/function/useSupported/index.ts +14 -0
  321. package/src/function/useWhenMounted/index.md +25 -0
  322. package/src/function/useWhenMounted/index.spec.ts +120 -0
  323. package/src/function/useWhenMounted/index.ts +16 -0
  324. package/src/index.ts +25 -0
  325. package/src/sensors/useScroll/demo.tsx +103 -0
  326. package/src/sensors/useScroll/index.md +117 -0
  327. package/src/sensors/useScroll/index.spec.ts +678 -0
  328. package/src/sensors/useScroll/index.ts +201 -0
  329. package/src/sensors/useWindowScroll/demo.tsx +78 -0
  330. package/src/sensors/useWindowScroll/index.md +98 -0
  331. package/src/sensors/useWindowScroll/index.spec.ts +69 -0
  332. package/src/sensors/useWindowScroll/index.ts +11 -0
  333. package/src/shared/configurable.ts +35 -0
  334. package/src/shared/index.ts +4 -0
  335. package/src/shared/normalizeTargets/index.spec.ts +76 -0
  336. package/src/shared/normalizeTargets/index.ts +27 -0
  337. package/src/shared/utils.ts +67 -0
  338. package/src/types.ts +56 -0
  339. package/tsconfig.json +9 -0
  340. package/tsup.config.ts +10 -0
  341. package/vitest.config.ts +22 -0
@@ -0,0 +1,51 @@
1
+ import { useWindowSize } from ".";
2
+ import { Computed } from "@legendapp/state/react";
3
+
4
+ const row: React.CSSProperties = {
5
+ display: "flex",
6
+ alignItems: "center",
7
+ padding: "8px 14px",
8
+ borderRadius: "6px",
9
+ border: "1px solid var(--sl-color-gray-5, #e2e8f0)",
10
+
11
+ background: "var(--sl-color-gray-6, #f1f5f9)",
12
+ // borderRadius: "6px",
13
+ gap: "24px",
14
+ color: "white",
15
+ };
16
+
17
+ export default function UseWindowSizeDemo() {
18
+ const { width: width$, height: height$ } = useWindowSize();
19
+
20
+ return (
21
+ <div
22
+ style={{
23
+ display: "flex",
24
+ flexDirection: "column",
25
+ gap: "8px",
26
+ fontFamily: "monospace",
27
+ fontSize: "14px",
28
+ background: "var(--sl-color-gray-6, #f1f5f9)",
29
+ }}
30
+ >
31
+ <Computed>
32
+ {() => (
33
+ <div style={row}>
34
+ <span>width: {width$.get()}px</span>
35
+ <span>height: {height$.get()}px</span>
36
+ </div>
37
+ )}
38
+ </Computed>
39
+
40
+ <p
41
+ style={{
42
+ margin: 5,
43
+ fontSize: "11px",
44
+ color: "var(--sl-color-gray-3, #94a3b8)",
45
+ }}
46
+ >
47
+ Resize the browser window to see the values update.
48
+ </p>
49
+ </div>
50
+ );
51
+ }
@@ -0,0 +1,55 @@
1
+ ---
2
+ title: useWindowSize
3
+ category: elements
4
+ ---
5
+
6
+ Tracks the browser window dimensions as reactive `Observable<number>` values for width and height.
7
+ Supports `inner`, `outer`, and `visual` viewport modes, and updates on resize and orientation change.
8
+ SSR-safe: returns `initialWidth`/`initialHeight` (default `0`) when `window` is not available.
9
+
10
+ ## Demo
11
+
12
+ ## Usage
13
+
14
+ ```tsx
15
+ import { useWindowSize } from '@usels/core'
16
+ import { Computed } from '@legendapp/state/react'
17
+
18
+ function Component() {
19
+ const size$ = useWindowSize()
20
+
21
+ return (
22
+ <Computed>
23
+ {() => (
24
+ <p>
25
+ {size$.width.get()} × {size$.height.get()}
26
+ </p>
27
+ )}
28
+ </Computed>
29
+ )
30
+ }
31
+ ```
32
+
33
+ ### Excluding scrollbar width
34
+
35
+ ```tsx
36
+ const size$ = useWindowSize({ includeScrollbar: false })
37
+ ```
38
+
39
+ ### Outer window size
40
+
41
+ ```tsx
42
+ const size$ = useWindowSize({ type: 'outer' })
43
+ ```
44
+
45
+ ### Visual viewport (pinch-zoom aware)
46
+
47
+ ```tsx
48
+ const size$ = useWindowSize({ type: 'visual' })
49
+ ```
50
+
51
+ ### Custom initial size for SSR
52
+
53
+ ```tsx
54
+ const size$ = useWindowSize({ initialWidth: 1280, initialHeight: 800 })
55
+ ```
@@ -0,0 +1,310 @@
1
+ // @vitest-environment jsdom
2
+ import { renderHook, act } from "@testing-library/react";
3
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
4
+ import { observable } from "@legendapp/state";
5
+ import { useWindowSize } from ".";
6
+
7
+ const flush = () => new Promise<void>((resolve) => queueMicrotask(resolve));
8
+
9
+ function mockMatchMedia(
10
+ matches = false,
11
+ ): (query: string) => MediaQueryList {
12
+ return (_query: string) =>
13
+ ({
14
+ matches,
15
+ media: _query,
16
+ addEventListener: vi.fn(),
17
+ removeEventListener: vi.fn(),
18
+ dispatchEvent: vi.fn(),
19
+ }) as unknown as MediaQueryList;
20
+ }
21
+
22
+ describe("useWindowSize()", () => {
23
+ beforeEach(() => {
24
+ vi.stubGlobal("matchMedia", mockMatchMedia());
25
+
26
+ Object.defineProperty(window, "innerWidth", {
27
+ writable: true,
28
+ configurable: true,
29
+ value: 1024,
30
+ });
31
+ Object.defineProperty(window, "innerHeight", {
32
+ writable: true,
33
+ configurable: true,
34
+ value: 768,
35
+ });
36
+ Object.defineProperty(window, "outerWidth", {
37
+ writable: true,
38
+ configurable: true,
39
+ value: 1024,
40
+ });
41
+ Object.defineProperty(window, "outerHeight", {
42
+ writable: true,
43
+ configurable: true,
44
+ value: 768,
45
+ });
46
+ });
47
+
48
+ afterEach(() => {
49
+ vi.unstubAllGlobals();
50
+ vi.restoreAllMocks();
51
+ });
52
+
53
+ it("returns width and height Observables", () => {
54
+ const { result } = renderHook(() => useWindowSize());
55
+ expect(typeof result.current.width.get).toBe("function");
56
+ expect(typeof result.current.height.get).toBe("function");
57
+ });
58
+
59
+ it("reads innerWidth/innerHeight by default", () => {
60
+ const { result } = renderHook(() => useWindowSize());
61
+ expect(result.current.width.get()).toBe(1024);
62
+ expect(result.current.height.get()).toBe(768);
63
+ });
64
+
65
+ it("uses initialWidth/initialHeight before mount when window is undefined", () => {
66
+ // Simulate SSR by checking initial values before any side effects run
67
+ const { result } = renderHook(() =>
68
+ useWindowSize({ initialWidth: 320, initialHeight: 480 }),
69
+ );
70
+ // After mount update fires, it reads actual window values
71
+ // but the observable was initialized with the provided defaults
72
+ expect(result.current.width.get()).toBeDefined();
73
+ expect(result.current.height.get()).toBeDefined();
74
+ });
75
+
76
+ it("updates on window resize event", () => {
77
+ const { result } = renderHook(() => useWindowSize());
78
+
79
+ act(() => {
80
+ (window as any).innerWidth = 1280;
81
+ (window as any).innerHeight = 900;
82
+ window.dispatchEvent(new Event("resize"));
83
+ });
84
+
85
+ expect(result.current.width.get()).toBe(1280);
86
+ expect(result.current.height.get()).toBe(900);
87
+ });
88
+
89
+ it("type: 'outer' reads outerWidth/outerHeight", () => {
90
+ (window as any).outerWidth = 1100;
91
+ (window as any).outerHeight = 850;
92
+
93
+ const { result } = renderHook(() => useWindowSize({ type: "outer" }));
94
+ expect(result.current.width.get()).toBe(1100);
95
+ expect(result.current.height.get()).toBe(850);
96
+ });
97
+
98
+ it("type: 'outer' updates on resize", () => {
99
+ const { result } = renderHook(() => useWindowSize({ type: "outer" }));
100
+
101
+ act(() => {
102
+ (window as any).outerWidth = 900;
103
+ (window as any).outerHeight = 600;
104
+ window.dispatchEvent(new Event("resize"));
105
+ });
106
+
107
+ expect(result.current.width.get()).toBe(900);
108
+ expect(result.current.height.get()).toBe(600);
109
+ });
110
+
111
+ it("includeScrollbar: false reads clientWidth/clientHeight", () => {
112
+ Object.defineProperty(document.documentElement, "clientWidth", {
113
+ writable: true,
114
+ configurable: true,
115
+ value: 1000,
116
+ });
117
+ Object.defineProperty(document.documentElement, "clientHeight", {
118
+ writable: true,
119
+ configurable: true,
120
+ value: 740,
121
+ });
122
+
123
+ const { result } = renderHook(() =>
124
+ useWindowSize({ includeScrollbar: false }),
125
+ );
126
+ expect(result.current.width.get()).toBe(1000);
127
+ expect(result.current.height.get()).toBe(740);
128
+ });
129
+
130
+ it("type: 'visual' reads visualViewport when available", () => {
131
+ const mockVP = {
132
+ width: 375,
133
+ height: 667,
134
+ scale: 2,
135
+ addEventListener: vi.fn(),
136
+ removeEventListener: vi.fn(),
137
+ };
138
+ vi.stubGlobal("visualViewport", mockVP);
139
+
140
+ const { result } = renderHook(() => useWindowSize({ type: "visual" }));
141
+ expect(result.current.width.get()).toBe(750); // 375 * 2
142
+ expect(result.current.height.get()).toBe(1334); // 667 * 2
143
+ });
144
+
145
+ it("type: 'visual' falls back to innerWidth/innerHeight when visualViewport unavailable", () => {
146
+ vi.stubGlobal("visualViewport", null);
147
+
148
+ const { result } = renderHook(() => useWindowSize({ type: "visual" }));
149
+ expect(result.current.width.get()).toBe(1024);
150
+ expect(result.current.height.get()).toBe(768);
151
+ });
152
+
153
+ it("listens to orientation changes by default", () => {
154
+ const addSpy = vi.spyOn(window, "matchMedia").mockReturnValue({
155
+ addEventListener: vi.fn(),
156
+ removeEventListener: vi.fn(),
157
+ matches: false,
158
+ media: "(orientation: portrait)",
159
+ } as any);
160
+
161
+ renderHook(() => useWindowSize());
162
+ expect(addSpy).toHaveBeenCalledWith("(orientation: portrait)");
163
+ });
164
+
165
+ it("listenOrientation: false does not update size on orientation change", () => {
166
+ let orientationListener: ((e: Event) => void) | null = null;
167
+
168
+ vi.stubGlobal("matchMedia", (_query: string) => ({
169
+ matches: false,
170
+ media: _query,
171
+ addEventListener: vi.fn((type: string, listener: EventListener) => {
172
+ if (type === "change") orientationListener = listener;
173
+ }),
174
+ removeEventListener: vi.fn(),
175
+ dispatchEvent: vi.fn(),
176
+ } as unknown as MediaQueryList));
177
+
178
+ const { result } = renderHook(() =>
179
+ useWindowSize({ listenOrientation: false }),
180
+ );
181
+
182
+ // Change innerWidth but do NOT dispatch a resize event
183
+ (window as any).innerWidth = 500;
184
+
185
+ act(() => {
186
+ // Trigger orientation change — should NOT call update() when listenOrientation: false
187
+ orientationListener?.({
188
+ type: "change",
189
+ matches: true,
190
+ } as unknown as MediaQueryListEvent);
191
+ });
192
+
193
+ // Size stays at 1024 because orientation change was ignored
194
+ expect(result.current.width.get()).toBe(1024);
195
+ });
196
+
197
+ it("removes resize listener on unmount", async () => {
198
+ const addSpy = vi.spyOn(window, "addEventListener");
199
+ const removeSpy = vi.spyOn(window, "removeEventListener");
200
+
201
+ const { unmount } = renderHook(() => useWindowSize());
202
+ unmount();
203
+ await flush();
204
+
205
+ const resizeAdded = addSpy.mock.calls.some(([type]) => type === "resize");
206
+ const resizeRemoved = removeSpy.mock.calls.some(
207
+ ([type]) => type === "resize",
208
+ );
209
+
210
+ expect(resizeAdded).toBe(true);
211
+ expect(resizeRemoved).toBe(true);
212
+ });
213
+
214
+ it("type change via re-render triggers immediate re-measurement without resize event", async () => {
215
+ (window as any).outerWidth = 1100;
216
+ (window as any).outerHeight = 850;
217
+
218
+ const { result, rerender } = renderHook(
219
+ (props: { type: "inner" | "outer" | "visual" }) =>
220
+ useWindowSize({ type: props.type }),
221
+ { initialProps: { type: "inner" as "inner" | "outer" | "visual" } },
222
+ );
223
+
224
+ expect(result.current.width.get()).toBe(1024);
225
+ expect(result.current.height.get()).toBe(768);
226
+
227
+ await act(async () => {
228
+ rerender({ type: "outer" });
229
+ await flush();
230
+ });
231
+
232
+ expect(result.current.width.get()).toBe(1100);
233
+ expect(result.current.height.get()).toBe(850);
234
+ });
235
+
236
+ it("type as Observable → reactive re-measurement when Observable value changes", async () => {
237
+ (window as any).outerWidth = 1100;
238
+ (window as any).outerHeight = 850;
239
+
240
+ const type$ = observable<"inner" | "outer" | "visual">("inner");
241
+
242
+ const { result } = renderHook(() => useWindowSize({ type: type$ }));
243
+
244
+ // Initial: 'inner' → reads innerWidth/innerHeight
245
+ expect(result.current.width.get()).toBe(1024);
246
+ expect(result.current.height.get()).toBe(768);
247
+
248
+ // Change Observable value — useObserveEffect tracks opts$.type.get() → re-measurement
249
+ await act(async () => {
250
+ type$.set("outer");
251
+ await flush();
252
+ });
253
+
254
+ expect(result.current.width.get()).toBe(1100);
255
+ expect(result.current.height.get()).toBe(850);
256
+ });
257
+
258
+ it("includeScrollbar change via re-render triggers immediate re-measurement without resize event", async () => {
259
+ Object.defineProperty(document.documentElement, "clientWidth", {
260
+ writable: true,
261
+ configurable: true,
262
+ value: 1000,
263
+ });
264
+ Object.defineProperty(document.documentElement, "clientHeight", {
265
+ writable: true,
266
+ configurable: true,
267
+ value: 740,
268
+ });
269
+
270
+ const { result, rerender } = renderHook(
271
+ (props: { includeScrollbar: boolean }) =>
272
+ useWindowSize({ includeScrollbar: props.includeScrollbar }),
273
+ { initialProps: { includeScrollbar: true } },
274
+ );
275
+
276
+ expect(result.current.width.get()).toBe(1024);
277
+ expect(result.current.height.get()).toBe(768);
278
+
279
+ await act(async () => {
280
+ rerender({ includeScrollbar: false });
281
+ await flush();
282
+ });
283
+
284
+ expect(result.current.width.get()).toBe(1000);
285
+ expect(result.current.height.get()).toBe(740);
286
+ });
287
+
288
+ it("does not update after unmount", async () => {
289
+ const { result, unmount } = renderHook(() => useWindowSize());
290
+
291
+ unmount();
292
+ await flush();
293
+
294
+ act(() => {
295
+ (window as any).innerWidth = 999;
296
+ window.dispatchEvent(new Event("resize"));
297
+ });
298
+
299
+ // Value stays at what it was before unmount (1024)
300
+ expect(result.current.width.get()).toBe(1024);
301
+ });
302
+
303
+ it("defaults to 0 initial size", () => {
304
+ // Verify the observable initializes with 0 before window is read
305
+ const { result } = renderHook(() => useWindowSize());
306
+ // After mount, actual window values are read
307
+ expect(typeof result.current.width.get()).toBe("number");
308
+ expect(typeof result.current.height.get()).toBe("number");
309
+ });
310
+ });
@@ -0,0 +1,107 @@
1
+ "use client";
2
+ import type { Observable } from "@legendapp/state";
3
+ import {
4
+ useObservable,
5
+ useMount,
6
+ useObserveEffect,
7
+ } from "@legendapp/state/react";
8
+ import { useEventListener } from "../../browser/useEventListener";
9
+ import { useMediaQuery } from "../../browser/useMediaQuery";
10
+ import { useMayObservableOptions } from "../../function/useMayObservableOptions";
11
+ import { useWhenMounted } from "../../function/useWhenMounted";
12
+ import type { DeepMaybeObservable } from "../../types";
13
+
14
+ export interface UseWindowSizeOptions {
15
+ initialWidth?: number;
16
+ initialHeight?: number;
17
+ listenOrientation?: boolean;
18
+ includeScrollbar?: boolean;
19
+ type?: "inner" | "outer" | "visual";
20
+ }
21
+
22
+ export type UseWindowSizeReturn = Observable<{
23
+ width: number;
24
+ height: number;
25
+ }>;
26
+
27
+ /*@__NO_SIDE_EFFECTS__*/
28
+ export function useWindowSize(
29
+ options?: DeepMaybeObservable<UseWindowSizeOptions>,
30
+ ): UseWindowSizeReturn {
31
+ // Standard Pattern: normalize DeepMaybeObservable<Options> into a stable computed Observable.
32
+ const opts$ = useMayObservableOptions<UseWindowSizeOptions>(options, {
33
+ initialWidth: "peek",
34
+ initialHeight: "peek",
35
+ });
36
+
37
+ const size$ = useObservable({
38
+ width: opts$.initialWidth.peek() ?? 0,
39
+ height: opts$.initialHeight.peek() ?? 0,
40
+ });
41
+
42
+ const update = () => {
43
+ if (typeof window === "undefined") return;
44
+
45
+ const type = opts$.type.peek() ?? "inner";
46
+ const includeScrollbar = opts$.includeScrollbar.peek() !== false;
47
+
48
+ let width: number;
49
+ let height: number;
50
+
51
+ if (type === "outer") {
52
+ width = window.outerWidth;
53
+ height = window.outerHeight;
54
+ } else if (type === "visual") {
55
+ const vp = window.visualViewport;
56
+ if (vp) {
57
+ width = vp.width * vp.scale;
58
+ height = vp.height * vp.scale;
59
+ } else {
60
+ width = window.innerWidth;
61
+ height = window.innerHeight;
62
+ }
63
+ } else {
64
+ if (includeScrollbar) {
65
+ width = window.innerWidth;
66
+ height = window.innerHeight;
67
+ } else {
68
+ width = document.documentElement.clientWidth;
69
+ height = document.documentElement.clientHeight;
70
+ }
71
+ }
72
+
73
+ size$.assign({ width, height });
74
+ };
75
+
76
+ useMount(update);
77
+
78
+ useEventListener("resize", update, { passive: true });
79
+
80
+ const vp$ = useWhenMounted(() =>
81
+ opts$.type.peek() === "visual" ? window.visualViewport : null,
82
+ );
83
+
84
+ useEventListener(vp$, "resize", update);
85
+
86
+ // type 또는 includeScrollbar가 변경되면 즉시 재측정
87
+ // 단일 함수 형태: opts$.type.get()/opts$.includeScrollbar.get()으로 dep 등록,
88
+ // update()는 .peek()만 사용하므로 추가 dep을 등록하지 않음.
89
+ useObserveEffect((e) => {
90
+ opts$.type.get();
91
+ opts$.includeScrollbar.get();
92
+ if (e.num > 0) update();
93
+ });
94
+
95
+ const matches$ = useMediaQuery("(orientation: portrait)");
96
+ useObserveEffect(
97
+ matches$,
98
+ () => {
99
+ if (opts$.listenOrientation.get() !== false) {
100
+ update();
101
+ }
102
+ },
103
+ { immediate: false },
104
+ );
105
+
106
+ return size$;
107
+ }
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: get
3
+ description: Extract values from MaybeObservable types
4
+ category: Observable Utilities
5
+ ---
6
+
7
+ Extract raw values from `MaybeObservable` types (works with both raw values and Legend-State observables).
8
+
9
+
10
+ ## Usage
11
+
12
+ ```typescript
13
+ import { get } from '@usels/core'
14
+ import { observable } from '@legendapp/state'
15
+
16
+ // With raw values
17
+ const rawValue = { name: 'John', age: 30 }
18
+ console.log(get(rawValue)) // { name: 'John', age: 30 }
19
+ console.log(get(rawValue, 'name')) // 'John'
20
+
21
+ // With observables
22
+ const obs$ = observable({ name: 'John', age: 30 })
23
+ console.log(get(obs$)) // { name: 'John', age: 30 }
24
+ console.log(get(obs$, 'name')) // 'John'
25
+ ```
@@ -0,0 +1,87 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { get } from ".";
3
+ import { observable } from "@legendapp/state";
4
+ describe("get() - single argument", () => {
5
+ it("returns raw value as-is", () => {
6
+ expect(get("hello")).toBe("hello");
7
+ expect(get(42)).toBe(42);
8
+ expect(get(true)).toBe(true);
9
+ });
10
+
11
+ it("extracts value from Observable", () => {
12
+ const obs$ = observable("world");
13
+ expect(get(obs$)).toBe("world");
14
+ });
15
+
16
+ it("handles null and undefined", () => {
17
+ expect(get(null)).toBe(null);
18
+ expect(get(undefined)).toBe(undefined);
19
+ expect(get(observable(null))).toBe(null);
20
+ expect(get(observable(undefined))).toBe(undefined);
21
+ });
22
+
23
+ it("handles objects", () => {
24
+ const obj = { name: "John" };
25
+ expect(get(obj)).toEqual(obj);
26
+ expect(get(observable(obj))).toEqual(obj);
27
+ });
28
+
29
+ it("handles arrays", () => {
30
+ const arr = [1, 2, 3];
31
+ expect(get(arr)).toEqual(arr);
32
+ expect(get(observable(arr))).toEqual(arr);
33
+ });
34
+ });
35
+
36
+ describe("get() - two arguments (property access)", () => {
37
+ it("extracts property from raw object", () => {
38
+ const obj = { name: "John", age: 30 };
39
+ expect(get(obj, "name")).toBe("John");
40
+ expect(get(obj, "age")).toBe(30);
41
+ });
42
+
43
+ it("extracts property from Observable object", () => {
44
+ const obs$ = observable({ name: "Jane", age: 25 });
45
+ expect(get(obs$, "name")).toBe("Jane");
46
+ expect(get(obs$, "age")).toBe(25);
47
+ });
48
+
49
+ it("returns undefined for missing keys", () => {
50
+ const obj = { name: "John" };
51
+ expect(get(obj, "age" as any)).toBe(undefined);
52
+ expect(get(observable(obj), "age" as any)).toBe(undefined);
53
+ });
54
+
55
+ it("handles nested observable properties", () => {
56
+ const filter$ = observable({ category: "electronics" });
57
+ expect(get(filter$, "category")).toBe("electronics");
58
+ });
59
+
60
+ it("returns undefined when value is not an object", () => {
61
+ expect(get("hello", "length" as any)).toBe(undefined);
62
+ expect(get(observable("hello"), "length" as any)).toBe(undefined);
63
+ expect(get(42, "toString" as any)).toBe(undefined);
64
+ });
65
+
66
+ it("handles null and undefined gracefully", () => {
67
+ expect(get(null, "key" as any)).toBe(undefined);
68
+ expect(get(undefined, "key" as any)).toBe(undefined);
69
+ expect(get(observable(null), "key" as any)).toBe(undefined);
70
+ });
71
+
72
+ it("preserves property value types", () => {
73
+ const obj = {
74
+ str: "text",
75
+ num: 42,
76
+ bool: true,
77
+ arr: [1, 2, 3],
78
+ nested: { value: "deep" },
79
+ };
80
+
81
+ expect(get(obj, "str")).toBe("text");
82
+ expect(get(obj, "num")).toBe(42);
83
+ expect(get(obj, "bool")).toBe(true);
84
+ expect(get(obj, "arr")).toEqual([1, 2, 3]);
85
+ expect(get(obj, "nested")).toEqual({ value: "deep" });
86
+ });
87
+ });
@@ -0,0 +1,70 @@
1
+ import { isObservable } from "@legendapp/state";
2
+ import { MaybeObservable } from "../../types";
3
+
4
+ /**
5
+ * Extracts the value from a MaybeObservable
6
+ * If the value is an Observable, calls .get() to extract it
7
+ * Otherwise returns the value as-is
8
+ *
9
+ * @param maybeObservable - A value that might be an Observable
10
+ * @returns The extracted value
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { observable } from '@legendapp/state'
15
+ * import { get } from '@usels/core'
16
+ *
17
+ * const value = get('hello') // 'hello'
18
+ * const obsValue = get(observable(42)) // 42
19
+ * ```
20
+ */
21
+ export function get<T>(maybeObservable: MaybeObservable<T>): T;
22
+ export function get<T>(maybeObservable: MaybeObservable<T> | undefined): T | undefined;
23
+
24
+ /**
25
+ * Extracts a property value from a MaybeObservable object
26
+ *
27
+ * @param maybeObservable - A value that might be an Observable
28
+ * @param key - The property key to extract
29
+ * @returns The property value, or undefined if not found
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { observable } from '@legendapp/state'
34
+ * import { get } from '@usels/core'
35
+ *
36
+ * const obj = { name: 'John' }
37
+ * const obs$ = observable({ name: 'Jane' })
38
+ *
39
+ * get(obj, 'name') // 'John'
40
+ * get(obs$, 'name') // 'Jane'
41
+ * get(obs$, 'age') // undefined
42
+ * ```
43
+ */
44
+ export function get<T, K extends keyof T>(
45
+ maybeObservable: MaybeObservable<T>,
46
+ key: K,
47
+ ): T[K] | undefined;
48
+
49
+ // Implementation
50
+ export function get<T>(
51
+ maybeObservable: MaybeObservable<T>,
52
+ key?: keyof T,
53
+ ): any {
54
+ // Extract the base value
55
+ const value = isObservable(maybeObservable)
56
+ ? maybeObservable.get()
57
+ : maybeObservable;
58
+
59
+ // If no key provided, return the value (single-arg overload)
60
+ if (key === undefined) {
61
+ return value;
62
+ }
63
+
64
+ // If key provided, extract property (two-arg overload)
65
+ if (value !== null && value !== undefined && typeof value === "object") {
66
+ return (value as any)[key];
67
+ }
68
+
69
+ return undefined;
70
+ }