@usels/core 0.0.1-beta.3

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 +82 -0
  11. package/dist/browser/useMediaQuery/demo.js.map +1 -0
  12. package/dist/browser/useMediaQuery/demo.mjs +62 -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 +86 -0
  41. package/dist/elements/useElementBounding/demo.js.map +1 -0
  42. package/dist/elements/useElementBounding/demo.mjs +66 -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 +82 -0
  53. package/dist/elements/useElementSize/demo.js.map +1 -0
  54. package/dist/elements/useElementSize/demo.mjs +62 -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 +103 -0
  89. package/dist/elements/useMouseInElement/demo.js.map +1 -0
  90. package/dist/elements/useMouseInElement/demo.mjs +83 -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 +100 -0
  143. package/dist/elements/useWindowFocus/demo.js.map +1 -0
  144. package/dist/elements/useWindowFocus/demo.mjs +80 -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 +78 -0
  155. package/dist/elements/useWindowSize/demo.js.map +1 -0
  156. package/dist/elements/useWindowSize/demo.mjs +58 -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 +121 -0
  203. package/dist/sensors/useScroll/demo.js.map +1 -0
  204. package/dist/sensors/useScroll/demo.mjs +101 -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 +84 -0
  215. package/dist/sensors/useWindowScroll/demo.js.map +1 -0
  216. package/dist/sensors/useWindowScroll/demo.mjs +64 -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 +58 -0
  259. package/src/browser/useMediaQuery/index.md +40 -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 +51 -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 +63 -0
  268. package/src/elements/useElementBounding/index.md +59 -0
  269. package/src/elements/useElementBounding/index.ts +159 -0
  270. package/src/elements/useElementSize/demo.tsx +48 -0
  271. package/src/elements/useElementSize/index.md +60 -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 +79 -0
  284. package/src/elements/useMouseInElement/index.md +71 -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 +56 -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 +71 -0
  304. package/src/elements/useWindowFocus/index.md +35 -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 +46 -0
  308. package/src/elements/useWindowSize/index.md +50 -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 +38 -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 +98 -0
  326. package/src/sensors/useScroll/index.md +112 -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 +69 -0
  330. package/src/sensors/useWindowScroll/index.md +88 -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,312 @@
1
+ // @vitest-environment jsdom
2
+ import { renderHook, act } from "@testing-library/react";
3
+ import { observable, ObservableHint } from "@legendapp/state";
4
+ import type { OpaqueObject } from "@legendapp/state";
5
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
6
+ import { useRef$ } from "../useRef$";
7
+ import { useResizeObserver } from ".";
8
+
9
+ const wrapEl = (el: Element) => observable<OpaqueObject<Element> | null>(ObservableHint.opaque(el));
10
+
11
+ // ---------------------------------------------------------------------------
12
+ // ResizeObserver mock
13
+ // ---------------------------------------------------------------------------
14
+
15
+ type ResizeObserverMockEntry = {
16
+ target: Element;
17
+ contentRect: DOMRectReadOnly;
18
+ };
19
+
20
+ class ResizeObserverMock {
21
+ static instances: ResizeObserverMock[] = [];
22
+
23
+ callback: ResizeObserverCallback;
24
+ observed: Element[] = [];
25
+ disconnected = false;
26
+
27
+ constructor(cb: ResizeObserverCallback) {
28
+ this.callback = cb;
29
+ ResizeObserverMock.instances.push(this);
30
+ }
31
+
32
+ observe(el: Element) {
33
+ this.observed.push(el);
34
+ }
35
+
36
+ unobserve(el: Element) {
37
+ this.observed = this.observed.filter((e) => e !== el);
38
+ }
39
+
40
+ disconnect() {
41
+ this.disconnected = true;
42
+ this.observed = [];
43
+ }
44
+
45
+ /** Helper: trigger the callback with a fake entry for the given element */
46
+ trigger(el: Element, rect: Partial<DOMRectReadOnly> = {}) {
47
+ if (this.disconnected) return;
48
+ const entry = {
49
+ target: el,
50
+ contentRect: { width: 100, height: 100, ...rect } as DOMRectReadOnly,
51
+ borderBoxSize: [],
52
+ contentBoxSize: [],
53
+ devicePixelContentBoxSize: [],
54
+ } as unknown as ResizeObserverEntry;
55
+ this.callback([entry], this);
56
+ }
57
+ }
58
+
59
+ beforeEach(() => {
60
+ ResizeObserverMock.instances = [];
61
+ vi.stubGlobal("ResizeObserver", ResizeObserverMock);
62
+ });
63
+
64
+ afterEach(() => {
65
+ vi.unstubAllGlobals();
66
+ });
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // useResizeObserver
70
+ // ---------------------------------------------------------------------------
71
+
72
+ describe("useResizeObserver()", () => {
73
+ it("calls callback when element resizes", () => {
74
+ const div = document.createElement("div");
75
+ const cb = vi.fn();
76
+
77
+ renderHook(() => useResizeObserver(wrapEl(div), cb));
78
+
79
+ const instance = ResizeObserverMock.instances.at(-1)!;
80
+ act(() => instance.trigger(div));
81
+
82
+ expect(cb).toHaveBeenCalledOnce();
83
+ });
84
+
85
+ it("observes multiple elements from an array", () => {
86
+ const a = document.createElement("div");
87
+ const b = document.createElement("span");
88
+ const cb = vi.fn();
89
+
90
+ renderHook(() => useResizeObserver([wrapEl(a), wrapEl(b)], cb));
91
+
92
+ const instance = ResizeObserverMock.instances.at(-1)!;
93
+ expect(instance.observed).toContain(a);
94
+ expect(instance.observed).toContain(b);
95
+ });
96
+
97
+ it("stop() disconnects the observer and suppresses further callbacks", () => {
98
+ const div = document.createElement("div");
99
+ const cb = vi.fn();
100
+
101
+ const { result } = renderHook(() => useResizeObserver(wrapEl(div), cb));
102
+
103
+ act(() => result.current.stop());
104
+
105
+ const instance = ResizeObserverMock.instances.at(-1)!;
106
+ expect(instance.disconnected).toBe(true);
107
+ act(() => instance.trigger(div));
108
+ expect(cb).not.toHaveBeenCalled();
109
+ });
110
+
111
+ it("passes box option to observe()", () => {
112
+ const div = document.createElement("div");
113
+ const observeSpy = vi.spyOn(ResizeObserverMock.prototype, "observe");
114
+
115
+ renderHook(() =>
116
+ useResizeObserver(wrapEl(div), vi.fn(), { box: "border-box" })
117
+ );
118
+
119
+ expect(observeSpy).toHaveBeenCalledWith(div, { box: "border-box" });
120
+ });
121
+
122
+ it("returns isSupported: true when ResizeObserver is available", () => {
123
+ const div = document.createElement("div");
124
+ const { result } = renderHook(() => useResizeObserver(wrapEl(div), vi.fn()));
125
+ expect(result.current.isSupported$.get()).toBe(true);
126
+ });
127
+
128
+ it("returns isSupported: false and skips setup when ResizeObserver is unavailable", () => {
129
+ vi.stubGlobal("ResizeObserver", undefined);
130
+
131
+ const div = document.createElement("div");
132
+ const cb = vi.fn();
133
+ const { result } = renderHook(() => useResizeObserver(wrapEl(div), cb));
134
+
135
+ expect(result.current.isSupported$.get()).toBe(false);
136
+ expect(ResizeObserverMock.instances).toHaveLength(0);
137
+ });
138
+
139
+ it("reacts to Ref$ target — starts observing after element is assigned", () => {
140
+ const cb = vi.fn();
141
+
142
+ const { result } = renderHook(() => {
143
+ const el$ = useRef$<HTMLDivElement>();
144
+ const ro = useResizeObserver(el$, cb);
145
+ return { el$, ro };
146
+ });
147
+
148
+ // Before element assigned — no active observer yet
149
+ const instancesBefore = ResizeObserverMock.instances.filter(
150
+ (i) => !i.disconnected && i.observed.length > 0
151
+ );
152
+ expect(instancesBefore).toHaveLength(0);
153
+
154
+ const div = document.createElement("div");
155
+ act(() => result.current.el$(div));
156
+
157
+ // After element assigned — observer should be active
158
+ const activeInstance = ResizeObserverMock.instances.find(
159
+ (i) => i.observed.includes(div)
160
+ );
161
+ expect(activeInstance).toBeDefined();
162
+ });
163
+
164
+ it("reacts to Observable<Element|null> target — starts observing after value is set", () => {
165
+ const target$ = observable<Element | null>(null);
166
+ const cb = vi.fn();
167
+
168
+ renderHook(() => useResizeObserver(target$ as any, cb));
169
+
170
+ // Initially null — no active observer with observed elements
171
+ const instancesWithObserved = ResizeObserverMock.instances.filter(
172
+ (i) => i.observed.length > 0
173
+ );
174
+ expect(instancesWithObserved).toHaveLength(0);
175
+
176
+ const div = document.createElement("div");
177
+ act(() => {
178
+ target$.set(div);
179
+ });
180
+
181
+ // After setting element, observer should be active
182
+ const activeInstance = ResizeObserverMock.instances.find(
183
+ (i) => i.observed.includes(div)
184
+ );
185
+ expect(activeInstance).toBeDefined();
186
+ });
187
+
188
+ it("handles mixed array of Ref$, Observable, and plain Element", () => {
189
+ const plainEl = document.createElement("section");
190
+ const obsEl = document.createElement("span");
191
+ const el$El = document.createElement("p");
192
+ const target$ = observable<Element | null>(obsEl);
193
+
194
+ const { result } = renderHook(() => {
195
+ const el$ = useRef$<HTMLParagraphElement>();
196
+ const ro = useResizeObserver([el$ as any, target$ as any, plainEl], vi.fn());
197
+ return { el$, ro };
198
+ });
199
+
200
+ // After mount: plainEl and obsEl observed, el$ not yet assigned
201
+ let instance = ResizeObserverMock.instances.at(-1)!;
202
+ expect(instance.observed).toContain(plainEl);
203
+ expect(instance.observed).toContain(obsEl);
204
+ expect(instance.observed).not.toContain(el$El);
205
+
206
+ // Assign Ref$ element
207
+ act(() => result.current.el$(el$El));
208
+
209
+ // After Ref$ assigned, all three observed
210
+ instance = ResizeObserverMock.instances.at(-1)!;
211
+ expect(instance.observed).toContain(el$El);
212
+ expect(instance.observed).toContain(obsEl);
213
+ expect(instance.observed).toContain(plainEl);
214
+ });
215
+
216
+ it("disconnects the active observer on unmount", () => {
217
+ const div = document.createElement("div");
218
+ const { unmount } = renderHook(() => useResizeObserver(wrapEl(div), vi.fn()));
219
+
220
+ const activeInstance = ResizeObserverMock.instances.at(-1)!;
221
+ expect(activeInstance.disconnected).toBe(false);
222
+
223
+ unmount();
224
+
225
+ expect(activeInstance.disconnected).toBe(true);
226
+ });
227
+
228
+ it("does not create an observer when target is an empty array", () => {
229
+ renderHook(() => useResizeObserver([], vi.fn()));
230
+
231
+ const activeInstances = ResizeObserverMock.instances.filter(
232
+ (i) => i.observed.length > 0,
233
+ );
234
+ expect(activeInstances).toHaveLength(0);
235
+ });
236
+
237
+ it("does not create an observer when target is null", () => {
238
+ renderHook(() => useResizeObserver(null as any, vi.fn()));
239
+
240
+ const activeInstances = ResizeObserverMock.instances.filter(
241
+ (i) => i.observed.length > 0,
242
+ );
243
+ expect(activeInstances).toHaveLength(0);
244
+ });
245
+
246
+ it("stops observing old element and observes new element when Ref$ target changes", () => {
247
+ const elA = document.createElement("div");
248
+ const elB = document.createElement("div");
249
+ const cb = vi.fn();
250
+
251
+ const { result } = renderHook(() => {
252
+ const el$ = useRef$<HTMLDivElement>();
253
+ return { el$, ro: useResizeObserver(el$ as any, cb) };
254
+ });
255
+
256
+ // Assign elA first
257
+ act(() => result.current.el$(elA));
258
+
259
+ expect(
260
+ ResizeObserverMock.instances.find((i) => !i.disconnected && i.observed.includes(elA)),
261
+ ).toBeDefined();
262
+
263
+ // Switch to elB
264
+ act(() => result.current.el$(elB));
265
+
266
+ // elB should now be observed
267
+ expect(
268
+ ResizeObserverMock.instances.find((i) => !i.disconnected && i.observed.includes(elB)),
269
+ ).toBeDefined();
270
+
271
+ // elA should no longer be observed by any active instance
272
+ expect(
273
+ ResizeObserverMock.instances.find((i) => !i.disconnected && i.observed.includes(elA)),
274
+ ).toBeUndefined();
275
+ });
276
+
277
+ it("uses the latest callback without recreating the observer on re-render", () => {
278
+ const div = document.createElement("div");
279
+ const cb1 = vi.fn();
280
+ const cb2 = vi.fn();
281
+
282
+ const { rerender } = renderHook(
283
+ ({ cb }) => useResizeObserver(wrapEl(div), cb),
284
+ { initialProps: { cb: cb1 } },
285
+ );
286
+
287
+ const instance = ResizeObserverMock.instances.at(-1)!;
288
+
289
+ rerender({ cb: cb2 });
290
+
291
+ // Observer must NOT be recreated — same instance as before
292
+ expect(ResizeObserverMock.instances.at(-1)).toBe(instance);
293
+
294
+ // Triggering should invoke the latest callback (cb2), not the stale one (cb1)
295
+ act(() => instance.trigger(div));
296
+ expect(cb1).not.toHaveBeenCalled();
297
+ expect(cb2).toHaveBeenCalledOnce();
298
+ });
299
+
300
+ it("passes device-pixel-content-box box option to observe()", () => {
301
+ const div = document.createElement("div");
302
+ const observeSpy = vi.spyOn(ResizeObserverMock.prototype, "observe");
303
+
304
+ renderHook(() =>
305
+ useResizeObserver(wrapEl(div), vi.fn(), { box: "device-pixel-content-box" }),
306
+ );
307
+
308
+ expect(observeSpy).toHaveBeenCalledWith(div, {
309
+ box: "device-pixel-content-box",
310
+ });
311
+ });
312
+ });
@@ -0,0 +1,106 @@
1
+ import type { Observable } from "@legendapp/state";
2
+ import { useObservable, useObserve } from "@legendapp/state/react";
3
+ import { useEffect, useRef } from "react";
4
+ import { normalizeTargets } from "../../shared/normalizeTargets";
5
+ import { MaybeElement } from "../useRef$";
6
+
7
+ export { normalizeTargets } from "../../shared/normalizeTargets";
8
+
9
+ export interface UseResizeObserverOptions {
10
+ box?: "content-box" | "border-box" | "device-pixel-content-box";
11
+ }
12
+
13
+ export interface UseResizeObserverReturn {
14
+ isSupported$: Observable<boolean>;
15
+ stop: () => void;
16
+ }
17
+
18
+ /**
19
+ * Observes one or more elements for size changes using the ResizeObserver API.
20
+ *
21
+ * @param target - Element(s) to observe: Ref$, Observable<Element|null>, plain Element, or an array
22
+ * @param callback - ResizeObserver callback. Wrap in `useCallback` to avoid stale closures —
23
+ * the observer is only recreated when targets change, not on every render.
24
+ * @param options - Optional box model option. Note: dynamic `box` changes are not reactively
25
+ * tracked; remount the hook or change a tracked target to pick up a new box value.
26
+ * @returns `{ isSupported$, stop }` — reactive support flag and manual stop function
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * const el$ = useRef$<HTMLDivElement>();
31
+ * const handleResize = useCallback<ResizeObserverCallback>((entries) => {
32
+ * const { width, height } = entries[0].contentRect;
33
+ * width$.set(width);
34
+ * }, []);
35
+ * useResizeObserver(el$, handleResize);
36
+ * return <div ref={el$} />;
37
+ * ```
38
+ */
39
+ export function useResizeObserver(
40
+ target: MaybeElement | MaybeElement[],
41
+ callback: ResizeObserverCallback,
42
+ options?: UseResizeObserverOptions,
43
+ ): UseResizeObserverReturn {
44
+ const isSupported$ = useObservable<boolean>(
45
+ typeof ResizeObserver !== "undefined",
46
+ );
47
+ const observerRef = useRef<ResizeObserver | null>(null);
48
+
49
+ // Always use the latest callback without recreating the observer on every render.
50
+ const callbackRef = useRef(callback);
51
+ callbackRef.current = callback;
52
+
53
+ // Always use the latest options in setup() without reactive tracking.
54
+ const optionsRef = useRef(options);
55
+ optionsRef.current = options;
56
+
57
+ // Guards useObserve's initial synchronous run (before DOM is committed) from
58
+ // calling setup(). Only useMount triggers the first setup, ensuring elements
59
+ // are available in the DOM before observation begins.
60
+ const mountedRef = useRef(false);
61
+
62
+ const cleanup = () => {
63
+ observerRef.current?.disconnect();
64
+ observerRef.current = null;
65
+ };
66
+
67
+ const setup = () => {
68
+ if (!isSupported$.peek()) return;
69
+ cleanup();
70
+
71
+ const targets = normalizeTargets(target);
72
+ if (!targets.length) return;
73
+
74
+ observerRef.current = new ResizeObserver((...args) =>
75
+ callbackRef.current(...args),
76
+ );
77
+ targets.forEach((el) => {
78
+ observerRef.current!.observe(el, { box: optionsRef.current?.box });
79
+ });
80
+ };
81
+
82
+ // Initial setup after DOM is committed; cleanup on unmount.
83
+ // useEffect is used directly (instead of useMount/useUnmount) because
84
+ // Legend-State's useEffectOnce delays cleanup via queueMicrotask in test
85
+ // environments, making synchronous post-unmount assertions unreliable.
86
+ // eslint-disable-next-line react-hooks/exhaustive-deps
87
+ useEffect(() => {
88
+ mountedRef.current = true;
89
+ setup();
90
+ return () => {
91
+ mountedRef.current = false;
92
+ cleanup();
93
+ };
94
+ }, []);
95
+
96
+ // Re-run setup whenever observable targets (Ref$ or Observable<Element>) change.
97
+ // Reading normalizeTargets(target) here registers observable dependencies so
98
+ // useObserve re-fires when a tracked target value changes.
99
+ // mountedRef guard prevents a redundant setup on the initial synchronous run.
100
+ useObserve(() => {
101
+ normalizeTargets(target);
102
+ if (mountedRef.current) setup();
103
+ });
104
+
105
+ return { isSupported$, stop: cleanup };
106
+ }
@@ -0,0 +1,71 @@
1
+ import { useWindowFocus } from ".";
2
+
3
+ const dot: React.CSSProperties = {
4
+ display: "inline-block",
5
+ width: "8px",
6
+ height: "8px",
7
+ borderRadius: "50%",
8
+ marginRight: "6px",
9
+ verticalAlign: "middle",
10
+ };
11
+
12
+ export default function UseWindowFocusDemo() {
13
+ const focused$ = useWindowFocus();
14
+
15
+ return (
16
+ <div
17
+ style={{
18
+ display: "flex",
19
+ flexDirection: "column",
20
+ gap: "10px",
21
+ fontFamily: "monospace",
22
+ fontSize: "13px",
23
+ }}
24
+ >
25
+ <div
26
+ style={{
27
+ display: "flex",
28
+ alignItems: "center",
29
+ padding: "10px 14px",
30
+ borderRadius: "6px",
31
+ border: `1px solid ${focused$.get() ? "var(--sl-color-green, #22c55e)" : "var(--sl-color-gray-4, #94a3b8)"}`,
32
+ background: focused$.get()
33
+ ? "var(--sl-color-green-low, #f0fdf4)"
34
+ : "var(--sl-color-gray-6, #f8fafc)",
35
+ transition: "border-color 0.2s, background 0.2s",
36
+ }}
37
+ >
38
+ <span
39
+ style={{
40
+ ...dot,
41
+ background: focused$.get()
42
+ ? "var(--sl-color-green, #22c55e)"
43
+ : "var(--sl-color-gray-4, #94a3b8)",
44
+ }}
45
+ />
46
+ <span>
47
+ focused$.get() ={" "}
48
+ <strong
49
+ style={{
50
+ color: focused$.get()
51
+ ? "var(--sl-color-green, #22c55e)"
52
+ : "var(--sl-color-gray-3, #64748b)",
53
+ }}
54
+ >
55
+ {String(focused$.get())}
56
+ </strong>
57
+ </span>
58
+ </div>
59
+
60
+ <p
61
+ style={{
62
+ margin: 0,
63
+ fontSize: "11px",
64
+ color: "var(--sl-color-gray-3, #94a3b8)",
65
+ }}
66
+ >
67
+ Click outside this window or switch tabs to see the value change.
68
+ </p>
69
+ </div>
70
+ );
71
+ }
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: useWindowFocus
3
+ category: elements
4
+ ---
5
+
6
+ Tracks whether the browser window currently has focus as a reactive `Observable<boolean>`.
7
+ Updates automatically when the user switches tabs, clicks away, or returns to the window.
8
+ SSR-safe: returns `false` when `document` is not available.
9
+
10
+ ## Demo
11
+
12
+ ## Usage
13
+
14
+ ```tsx
15
+ import { useWindowFocus } from '@usels/core'
16
+
17
+ function Component() {
18
+ const focused$ = useWindowFocus()
19
+
20
+ return (
21
+ <p>Window is {focused$.get() ? 'focused' : 'blurred'}</p>
22
+ )
23
+ }
24
+ ```
25
+
26
+ ### Pausing work when the window loses focus
27
+
28
+ ```tsx
29
+ const focused$ = useWindowFocus()
30
+
31
+ useObserve(() => {
32
+ if (!focused$.get()) pausePolling()
33
+ else resumePolling()
34
+ })
35
+ ```
@@ -0,0 +1,103 @@
1
+ // @vitest-environment jsdom
2
+ import { renderHook, act } from "@testing-library/react";
3
+ import { describe, it, expect, vi, afterEach } from "vitest";
4
+ import { useWindowFocus } from ".";
5
+
6
+ const flush = () => new Promise<void>((resolve) => queueMicrotask(resolve));
7
+
8
+ describe("useWindowFocus()", () => {
9
+ afterEach(() => {
10
+ vi.unstubAllGlobals();
11
+ });
12
+
13
+ it("returns an Observable", () => {
14
+ const { result } = renderHook(() => useWindowFocus());
15
+ expect(typeof result.current.get).toBe("function");
16
+ expect(typeof result.current.set).toBe("function");
17
+ });
18
+
19
+ it("initial value reflects document.hasFocus()", () => {
20
+ const hasFocusSpy = vi.spyOn(document, "hasFocus").mockReturnValue(true);
21
+ const { result } = renderHook(() => useWindowFocus());
22
+ expect(result.current.get()).toBe(true);
23
+ hasFocusSpy.mockRestore();
24
+ });
25
+
26
+ it("initial value is false when document.hasFocus() returns false", () => {
27
+ const hasFocusSpy = vi.spyOn(document, "hasFocus").mockReturnValue(false);
28
+ const { result } = renderHook(() => useWindowFocus());
29
+ expect(result.current.get()).toBe(false);
30
+ hasFocusSpy.mockRestore();
31
+ });
32
+
33
+ it("sets to true when window focus event fires", () => {
34
+ vi.spyOn(document, "hasFocus").mockReturnValue(false);
35
+ const { result } = renderHook(() => useWindowFocus());
36
+
37
+ act(() => {
38
+ window.dispatchEvent(new Event("focus"));
39
+ });
40
+
41
+ expect(result.current.get()).toBe(true);
42
+ });
43
+
44
+ it("sets to false when window blur event fires", () => {
45
+ vi.spyOn(document, "hasFocus").mockReturnValue(true);
46
+ const { result } = renderHook(() => useWindowFocus());
47
+
48
+ act(() => {
49
+ window.dispatchEvent(new Event("blur"));
50
+ });
51
+
52
+ expect(result.current.get()).toBe(false);
53
+ });
54
+
55
+ it("toggles correctly across multiple focus/blur events", () => {
56
+ vi.spyOn(document, "hasFocus").mockReturnValue(false);
57
+ const { result } = renderHook(() => useWindowFocus());
58
+
59
+ act(() => { window.dispatchEvent(new Event("focus")); });
60
+ expect(result.current.get()).toBe(true);
61
+
62
+ act(() => { window.dispatchEvent(new Event("blur")); });
63
+ expect(result.current.get()).toBe(false);
64
+
65
+ act(() => { window.dispatchEvent(new Event("focus")); });
66
+ expect(result.current.get()).toBe(true);
67
+ });
68
+
69
+ it("removes event listeners on unmount", async () => {
70
+ const addSpy = vi.spyOn(window, "addEventListener");
71
+ const removeSpy = vi.spyOn(window, "removeEventListener");
72
+
73
+ const { unmount } = renderHook(() => useWindowFocus());
74
+ unmount();
75
+ await flush(); // useMount defers cleanup via queueMicrotask in test env
76
+
77
+ const focusAdded = addSpy.mock.calls.some(([type]) => type === "focus");
78
+ const blurAdded = addSpy.mock.calls.some(([type]) => type === "blur");
79
+ const focusRemoved = removeSpy.mock.calls.some(([type]) => type === "focus");
80
+ const blurRemoved = removeSpy.mock.calls.some(([type]) => type === "blur");
81
+
82
+ expect(focusAdded).toBe(true);
83
+ expect(blurAdded).toBe(true);
84
+ expect(focusRemoved).toBe(true);
85
+ expect(blurRemoved).toBe(true);
86
+
87
+ addSpy.mockRestore();
88
+ removeSpy.mockRestore();
89
+ });
90
+
91
+ it("does not respond to events after unmount", async () => {
92
+ vi.spyOn(document, "hasFocus").mockReturnValue(false);
93
+ const { result, unmount } = renderHook(() => useWindowFocus());
94
+
95
+ unmount();
96
+ await flush(); // wait for cleanup
97
+
98
+ act(() => { window.dispatchEvent(new Event("focus")); });
99
+
100
+ // Value stays at initial false — no listener active after cleanup
101
+ expect(result.current.get()).toBe(false);
102
+ });
103
+ });
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import type { Observable } from "@legendapp/state";
3
+ import { useObservable } from "@legendapp/state/react";
4
+ import { useMount } from "@legendapp/state/react";
5
+ import { useEventListener } from "../../browser/useEventListener";
6
+
7
+ /*@__NO_SIDE_EFFECTS__*/
8
+ export function useWindowFocus(): Observable<boolean> {
9
+ // Always initialize with false to match SSR output and avoid hydration mismatch.
10
+ // The actual value is synced after mount.
11
+ const focused$ = useObservable<boolean>(false);
12
+
13
+ useMount(() => {
14
+ focused$.set(document.hasFocus());
15
+ });
16
+
17
+ useEventListener("focus", () => focused$.set(true), { passive: true });
18
+ useEventListener("blur", () => focused$.set(false), { passive: true });
19
+
20
+ return focused$;
21
+ }
@@ -0,0 +1,46 @@
1
+ import { useWindowSize } from ".";
2
+
3
+ const row: React.CSSProperties = {
4
+ display: "flex",
5
+ alignItems: "center",
6
+ padding: "8px 14px",
7
+ borderRadius: "6px",
8
+ border: "1px solid var(--sl-color-gray-5, #e2e8f0)",
9
+
10
+ background: "var(--sl-color-gray-6, #f1f5f9)",
11
+ // borderRadius: "6px",
12
+ gap: "24px",
13
+ color: "white",
14
+ };
15
+
16
+ export default function UseWindowSizeDemo() {
17
+ const { width: width$, height: height$ } = useWindowSize();
18
+
19
+ return (
20
+ <div
21
+ style={{
22
+ display: "flex",
23
+ flexDirection: "column",
24
+ gap: "8px",
25
+ fontFamily: "monospace",
26
+ fontSize: "14px",
27
+ background: "var(--sl-color-gray-6, #f1f5f9)",
28
+ }}
29
+ >
30
+ <div style={row}>
31
+ <span>width: {width$.get()}px</span>
32
+ <span>height: {height$.get()}px</span>
33
+ </div>
34
+
35
+ <p
36
+ style={{
37
+ margin: 5,
38
+ fontSize: "11px",
39
+ color: "var(--sl-color-gray-3, #94a3b8)",
40
+ }}
41
+ >
42
+ Resize the browser window to see the values update.
43
+ </p>
44
+ </div>
45
+ );
46
+ }