@stacksjs/composables 0.70.88 → 0.70.91

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 (333) hide show
  1. package/dist/_shared.d.ts +49 -0
  2. package/dist/_shared.js +23 -0
  3. package/dist/cloneFnJSON.d.ts +5 -0
  4. package/dist/cloneFnJSON.js +3 -0
  5. package/dist/computedAsync.d.ts +28 -0
  6. package/dist/computedAsync.js +20 -0
  7. package/dist/computedEager.d.ts +27 -0
  8. package/dist/computedEager.js +10 -0
  9. package/dist/createEventHook.d.ts +16 -0
  10. package/dist/createEventHook.js +15 -0
  11. package/dist/createFetch.d.ts +14 -0
  12. package/dist/createFetch.js +8 -0
  13. package/dist/createGlobalState.d.ts +17 -0
  14. package/dist/createGlobalState.js +10 -0
  15. package/dist/createSharedComposable.d.ts +8 -0
  16. package/dist/createSharedComposable.js +9 -0
  17. package/dist/extendRef.d.ts +9 -0
  18. package/dist/extendRef.js +6 -0
  19. package/dist/formatTimeAgo.d.ts +23 -0
  20. package/dist/formatTimeAgo.js +33 -0
  21. package/dist/index.d.ts +271 -0
  22. package/dist/index.js +210 -0
  23. package/dist/isDefined.d.ts +5 -0
  24. package/dist/isDefined.js +3 -0
  25. package/dist/makeDestructurable.d.ts +18 -0
  26. package/dist/makeDestructurable.js +16 -0
  27. package/dist/onClickOutside.d.ts +14 -0
  28. package/dist/onClickOutside.js +25 -0
  29. package/dist/onKeyStroke.d.ts +26 -0
  30. package/dist/onKeyStroke.js +31 -0
  31. package/dist/onLongPress.d.ts +14 -0
  32. package/dist/onLongPress.js +43 -0
  33. package/dist/onStartTyping.d.ts +8 -0
  34. package/dist/onStartTyping.js +23 -0
  35. package/dist/refAutoReset.d.ts +11 -0
  36. package/dist/refAutoReset.js +15 -0
  37. package/dist/refDefault.d.ts +9 -0
  38. package/dist/refDefault.js +8 -0
  39. package/dist/resolveRef.d.ts +7 -0
  40. package/dist/resolveRef.js +7 -0
  41. package/dist/ssrHandlers.d.ts +13 -0
  42. package/dist/ssrHandlers.js +8 -0
  43. package/dist/syncRef.d.ts +21 -0
  44. package/dist/syncRef.js +35 -0
  45. package/dist/tryOnMounted.d.ts +22 -0
  46. package/dist/tryOnMounted.js +22 -0
  47. package/dist/unrefElement.d.ts +6 -0
  48. package/dist/unrefElement.js +9 -0
  49. package/dist/until.d.ts +34 -0
  50. package/dist/until.js +62 -0
  51. package/dist/useActiveElement.d.ts +6 -0
  52. package/dist/useActiveElement.js +19 -0
  53. package/dist/useAnimate.d.ts +18 -0
  54. package/dist/useAnimate.js +48 -0
  55. package/dist/useArrayUtils.d.ts +42 -0
  56. package/dist/useArrayUtils.js +114 -0
  57. package/dist/useAsyncQueue.d.ts +18 -0
  58. package/dist/useAsyncQueue.js +22 -0
  59. package/dist/useAsyncState.d.ts +23 -0
  60. package/dist/useAsyncState.js +35 -0
  61. package/dist/useBase64.d.ts +12 -0
  62. package/dist/useBase64.js +45 -0
  63. package/dist/useBattery.d.ts +15 -0
  64. package/dist/useBattery.js +38 -0
  65. package/dist/useBreakpoints.d.ts +96 -0
  66. package/dist/useBreakpoints.js +97 -0
  67. package/dist/useBroadcastChannel.d.ts +14 -0
  68. package/dist/useBroadcastChannel.js +31 -0
  69. package/dist/useBrowserLocation.d.ts +18 -0
  70. package/dist/useBrowserLocation.js +64 -0
  71. package/dist/useClipboard.d.ts +17 -0
  72. package/dist/useClipboard.js +32 -0
  73. package/dist/useClipboardItems.d.ts +11 -0
  74. package/dist/useClipboardItems.js +15 -0
  75. package/dist/useCloned.d.ts +15 -0
  76. package/dist/useCloned.js +16 -0
  77. package/dist/useColorMode.d.ts +18 -0
  78. package/dist/useColorMode.js +60 -0
  79. package/dist/useConfirmDialog.d.ts +14 -0
  80. package/dist/useConfirmDialog.js +34 -0
  81. package/dist/useCounter.d.ts +20 -0
  82. package/dist/useCounter.js +28 -0
  83. package/dist/useCssVar.d.ts +10 -0
  84. package/dist/useCssVar.js +23 -0
  85. package/dist/useCycleList.d.ts +18 -0
  86. package/dist/useCycleList.js +27 -0
  87. package/dist/useDark.d.ts +11 -0
  88. package/dist/useDark.js +38 -0
  89. package/dist/useDateFormat.d.ts +10 -0
  90. package/dist/useDateFormat.js +11 -0
  91. package/dist/useDebounce.d.ts +10 -0
  92. package/dist/useDebounce.js +16 -0
  93. package/dist/useDebounceFn.d.ts +10 -0
  94. package/dist/useDebounceFn.js +18 -0
  95. package/dist/useDebouncedRef.d.ts +11 -0
  96. package/dist/useDebouncedRef.js +22 -0
  97. package/dist/useDebouncedRefHistory.d.ts +5 -0
  98. package/dist/useDebouncedRefHistory.js +36 -0
  99. package/dist/useDeviceMotion.d.ts +27 -0
  100. package/dist/useDeviceMotion.js +53 -0
  101. package/dist/useDeviceOrientation.d.ts +15 -0
  102. package/dist/useDeviceOrientation.js +23 -0
  103. package/dist/useDevicePixelRatio.d.ts +5 -0
  104. package/dist/useDevicePixelRatio.js +24 -0
  105. package/dist/useDocumentVisibility.d.ts +5 -0
  106. package/dist/useDocumentVisibility.js +16 -0
  107. package/dist/useDraggable.d.ts +23 -0
  108. package/dist/useDraggable.js +58 -0
  109. package/dist/useDropZone.d.ts +15 -0
  110. package/dist/useDropZone.js +52 -0
  111. package/dist/useElementBounding.d.ts +21 -0
  112. package/dist/useElementBounding.js +59 -0
  113. package/dist/useElementByPoint.d.ts +10 -0
  114. package/dist/useElementByPoint.js +18 -0
  115. package/dist/useElementHover.d.ts +9 -0
  116. package/dist/useElementHover.js +28 -0
  117. package/dist/useElementSize.d.ts +19 -0
  118. package/dist/useElementSize.js +34 -0
  119. package/dist/useElementVisibility.d.ts +10 -0
  120. package/dist/useElementVisibility.js +10 -0
  121. package/dist/useEventBus.d.ts +14 -0
  122. package/dist/useEventBus.js +41 -0
  123. package/dist/useEventListener.d.ts +14 -0
  124. package/dist/useEventListener.js +29 -0
  125. package/dist/useEventSource.d.ts +32 -0
  126. package/dist/useEventSource.js +72 -0
  127. package/dist/useEyeDropper.d.ts +10 -0
  128. package/dist/useEyeDropper.js +17 -0
  129. package/dist/useFavicon.d.ts +8 -0
  130. package/dist/useFavicon.js +22 -0
  131. package/dist/useFetch.d.ts +35 -0
  132. package/dist/useFetch.js +61 -0
  133. package/dist/useFileDialog.d.ts +15 -0
  134. package/dist/useFileDialog.js +24 -0
  135. package/dist/useFocus.d.ts +13 -0
  136. package/dist/useFocus.js +42 -0
  137. package/dist/useFocusWithin.d.ts +9 -0
  138. package/dist/useFocusWithin.js +29 -0
  139. package/dist/useForm.d.ts +97 -0
  140. package/dist/useForm.js +182 -0
  141. package/dist/useFps.d.ts +7 -0
  142. package/dist/useFps.js +22 -0
  143. package/dist/useFullscreen.d.ts +16 -0
  144. package/dist/useFullscreen.js +67 -0
  145. package/dist/useGeolocation.d.ts +26 -0
  146. package/dist/useGeolocation.js +55 -0
  147. package/dist/useIdle.d.ts +18 -0
  148. package/dist/useIdle.js +46 -0
  149. package/dist/useImage.d.ts +18 -0
  150. package/dist/useImage.js +32 -0
  151. package/dist/useInfiniteScroll.d.ts +11 -0
  152. package/dist/useInfiniteScroll.js +50 -0
  153. package/dist/useIntersectionObserver.d.ts +16 -0
  154. package/dist/useIntersectionObserver.js +27 -0
  155. package/dist/useInterval.d.ts +13 -0
  156. package/dist/useInterval.js +32 -0
  157. package/dist/useIntervalFn.d.ts +16 -0
  158. package/dist/useIntervalFn.js +24 -0
  159. package/dist/useKeyModifier.d.ts +6 -0
  160. package/dist/useKeyModifier.js +22 -0
  161. package/dist/useLastChanged.d.ts +11 -0
  162. package/dist/useLastChanged.js +8 -0
  163. package/dist/useLocalStorage.d.ts +17 -0
  164. package/dist/useLocalStorage.js +4 -0
  165. package/dist/useMagicKeys.d.ts +16 -0
  166. package/dist/useMagicKeys.js +81 -0
  167. package/dist/useManualRefHistory.d.ts +27 -0
  168. package/dist/useManualRefHistory.js +64 -0
  169. package/dist/useMath.d.ts +17 -0
  170. package/dist/useMath.js +52 -0
  171. package/dist/useMediaQuery.d.ts +9 -0
  172. package/dist/useMediaQuery.js +19 -0
  173. package/dist/useMemoize.d.ts +13 -0
  174. package/dist/useMemoize.js +24 -0
  175. package/dist/useMounted.d.ts +6 -0
  176. package/dist/useMounted.js +8 -0
  177. package/dist/useMouse.d.ts +19 -0
  178. package/dist/useMouse.js +67 -0
  179. package/dist/useMouseInElement.d.ts +17 -0
  180. package/dist/useMouseInElement.js +31 -0
  181. package/dist/useMousePressed.d.ts +10 -0
  182. package/dist/useMousePressed.js +31 -0
  183. package/dist/useMutationObserver.d.ts +16 -0
  184. package/dist/useMutationObserver.js +27 -0
  185. package/dist/useNavigatorLanguage.d.ts +5 -0
  186. package/dist/useNavigatorLanguage.js +17 -0
  187. package/dist/useNetwork.d.ts +18 -0
  188. package/dist/useNetwork.js +58 -0
  189. package/dist/useNow.d.ts +8 -0
  190. package/dist/useNow.js +10 -0
  191. package/dist/useObjectUrl.d.ts +8 -0
  192. package/dist/useObjectUrl.js +23 -0
  193. package/dist/useOffsetPagination.d.ts +21 -0
  194. package/dist/useOffsetPagination.js +45 -0
  195. package/dist/useOnline.d.ts +7 -0
  196. package/dist/useOnline.js +20 -0
  197. package/dist/usePageLeave.d.ts +9 -0
  198. package/dist/usePageLeave.js +27 -0
  199. package/dist/useParallax.d.ts +15 -0
  200. package/dist/useParallax.js +33 -0
  201. package/dist/useParentElement.d.ts +6 -0
  202. package/dist/useParentElement.js +8 -0
  203. package/dist/usePermission.d.ts +7 -0
  204. package/dist/usePermission.js +21 -0
  205. package/dist/usePointer.d.ts +15 -0
  206. package/dist/usePointer.js +32 -0
  207. package/dist/usePointerLock.d.ts +13 -0
  208. package/dist/usePointerLock.js +33 -0
  209. package/dist/usePointerSwipe.d.ts +20 -0
  210. package/dist/usePointerSwipe.js +52 -0
  211. package/dist/usePreferredColorScheme.d.ts +6 -0
  212. package/dist/usePreferredColorScheme.js +25 -0
  213. package/dist/usePreferredContrast.d.ts +6 -0
  214. package/dist/usePreferredContrast.js +29 -0
  215. package/dist/usePreferredLanguages.d.ts +5 -0
  216. package/dist/usePreferredLanguages.js +16 -0
  217. package/dist/usePreferredReducedMotion.d.ts +6 -0
  218. package/dist/usePreferredReducedMotion.js +18 -0
  219. package/dist/usePrevious.d.ts +9 -0
  220. package/dist/usePrevious.js +8 -0
  221. package/dist/useQuery.d.ts +106 -0
  222. package/dist/useQuery.js +265 -0
  223. package/dist/useRafFn.d.ts +19 -0
  224. package/dist/useRafFn.js +37 -0
  225. package/dist/useRefHistory.d.ts +28 -0
  226. package/dist/useRefHistory.js +72 -0
  227. package/dist/useResizeObserver.d.ts +16 -0
  228. package/dist/useResizeObserver.js +27 -0
  229. package/dist/useScreenOrientation.d.ts +13 -0
  230. package/dist/useScreenOrientation.js +27 -0
  231. package/dist/useScreenSafeArea.d.ts +12 -0
  232. package/dist/useScreenSafeArea.js +25 -0
  233. package/dist/useScriptTag.d.ts +20 -0
  234. package/dist/useScriptTag.js +52 -0
  235. package/dist/useScroll.d.ts +36 -0
  236. package/dist/useScroll.js +116 -0
  237. package/dist/useScrollLock.d.ts +10 -0
  238. package/dist/useScrollLock.js +39 -0
  239. package/dist/useSessionStorage.d.ts +17 -0
  240. package/dist/useSessionStorage.js +4 -0
  241. package/dist/useShare.d.ts +15 -0
  242. package/dist/useShare.js +11 -0
  243. package/dist/useSorted.d.ts +10 -0
  244. package/dist/useSorted.js +10 -0
  245. package/dist/useStepper.d.ts +23 -0
  246. package/dist/useStepper.js +46 -0
  247. package/dist/useStorage.d.ts +18 -0
  248. package/dist/useStorage.js +54 -0
  249. package/dist/useStyleTag.d.ts +17 -0
  250. package/dist/useStyleTag.js +39 -0
  251. package/dist/useSupported.d.ts +8 -0
  252. package/dist/useSupported.js +10 -0
  253. package/dist/useSwipe.d.ts +20 -0
  254. package/dist/useSwipe.js +58 -0
  255. package/dist/useTextDirection.d.ts +9 -0
  256. package/dist/useTextDirection.js +16 -0
  257. package/dist/useTextSelection.d.ts +10 -0
  258. package/dist/useTextSelection.js +27 -0
  259. package/dist/useTextareaAutosize.d.ts +10 -0
  260. package/dist/useTextareaAutosize.js +20 -0
  261. package/dist/useThrottle.d.ts +9 -0
  262. package/dist/useThrottle.js +23 -0
  263. package/dist/useThrottleFn.d.ts +11 -0
  264. package/dist/useThrottleFn.js +36 -0
  265. package/dist/useThrottledRef.d.ts +11 -0
  266. package/dist/useThrottledRef.js +30 -0
  267. package/dist/useThrottledRefHistory.d.ts +5 -0
  268. package/dist/useThrottledRefHistory.js +43 -0
  269. package/dist/useTimeAgo.d.ts +16 -0
  270. package/dist/useTimeAgo.js +58 -0
  271. package/dist/useTimeout.d.ts +12 -0
  272. package/dist/useTimeout.js +32 -0
  273. package/dist/useTimeoutFn.d.ts +16 -0
  274. package/dist/useTimeoutFn.js +27 -0
  275. package/dist/useTimeoutPoll.d.ts +10 -0
  276. package/dist/useTimeoutPoll.js +33 -0
  277. package/dist/useTimestamp.d.ts +15 -0
  278. package/dist/useTimestamp.js +43 -0
  279. package/dist/useTitle.d.ts +10 -0
  280. package/dist/useTitle.js +12 -0
  281. package/dist/useToNumber.d.ts +11 -0
  282. package/dist/useToNumber.js +25 -0
  283. package/dist/useToString.d.ts +6 -0
  284. package/dist/useToString.js +10 -0
  285. package/dist/useToggle.d.ts +6 -0
  286. package/dist/useToggle.js +12 -0
  287. package/dist/useTransition.d.ts +28 -0
  288. package/dist/useTransition.js +89 -0
  289. package/dist/useUrlSearchParams.d.ts +18 -0
  290. package/dist/useUrlSearchParams.js +72 -0
  291. package/dist/useVibrate.d.ts +13 -0
  292. package/dist/useVibrate.js +14 -0
  293. package/dist/useVirtualList.d.ts +23 -0
  294. package/dist/useVirtualList.js +49 -0
  295. package/dist/useWakeLock.d.ts +12 -0
  296. package/dist/useWakeLock.js +32 -0
  297. package/dist/useWebNotification.d.ts +25 -0
  298. package/dist/useWebNotification.js +39 -0
  299. package/dist/useWebSocket.d.ts +38 -0
  300. package/dist/useWebSocket.js +103 -0
  301. package/dist/useWebWorker.d.ts +18 -0
  302. package/dist/useWebWorker.js +56 -0
  303. package/dist/useWindowFocus.d.ts +5 -0
  304. package/dist/useWindowFocus.js +20 -0
  305. package/dist/useWindowScroll.d.ts +9 -0
  306. package/dist/useWindowScroll.js +17 -0
  307. package/dist/useWindowSize.d.ts +15 -0
  308. package/dist/useWindowSize.js +28 -0
  309. package/dist/watchArray.d.ts +5 -0
  310. package/dist/watchArray.js +9 -0
  311. package/dist/watchAtMost.d.ts +5 -0
  312. package/dist/watchAtMost.js +12 -0
  313. package/dist/watchDebounced.d.ts +23 -0
  314. package/dist/watchDebounced.js +20 -0
  315. package/dist/watchDeep.d.ts +7 -0
  316. package/dist/watchDeep.js +13 -0
  317. package/dist/watchIgnorable.d.ts +12 -0
  318. package/dist/watchIgnorable.js +19 -0
  319. package/dist/watchImmediate.d.ts +5 -0
  320. package/dist/watchImmediate.js +7 -0
  321. package/dist/watchOnce.d.ts +19 -0
  322. package/dist/watchOnce.js +17 -0
  323. package/dist/watchPausable.d.ts +13 -0
  324. package/dist/watchPausable.js +23 -0
  325. package/dist/watchThrottled.d.ts +23 -0
  326. package/dist/watchThrottled.js +37 -0
  327. package/dist/watchTriggerable.d.ts +5 -0
  328. package/dist/watchTriggerable.js +10 -0
  329. package/dist/watchWithFilter.d.ts +7 -0
  330. package/dist/watchWithFilter.js +6 -0
  331. package/dist/whenever.d.ts +18 -0
  332. package/dist/whenever.js +7 -0
  333. package/package.json +2 -2
@@ -0,0 +1,29 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ export function usePreferredContrast() {
3
+ const contrast = ref("no-preference");
4
+ if (typeof window > "u" || !window.matchMedia)
5
+ return contrast;
6
+ const more = window.matchMedia("(prefers-contrast: more)"), less = window.matchMedia("(prefers-contrast: less)"), custom = window.matchMedia("(prefers-contrast: custom)");
7
+ function update() {
8
+ if (more.matches)
9
+ contrast.value = "more";
10
+ else if (less.matches)
11
+ contrast.value = "less";
12
+ else if (custom.matches)
13
+ contrast.value = "custom";
14
+ else
15
+ contrast.value = "no-preference";
16
+ }
17
+ update();
18
+ more.addEventListener("change", update);
19
+ less.addEventListener("change", update);
20
+ custom.addEventListener("change", update);
21
+ try {
22
+ onUnmounted(() => {
23
+ more.removeEventListener("change", update);
24
+ less.removeEventListener("change", update);
25
+ custom.removeEventListener("change", update);
26
+ });
27
+ } catch {}
28
+ return contrast;
29
+ }
@@ -0,0 +1,5 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Reactive `navigator.languages`. Returns the user's preferred languages.
4
+ */
5
+ export declare function usePreferredLanguages(): Ref<readonly string[]>;
@@ -0,0 +1,16 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ export function usePreferredLanguages() {
3
+ const languages = ref(typeof navigator < "u" ? navigator.languages : []);
4
+ if (typeof window > "u")
5
+ return languages;
6
+ const handler = () => {
7
+ languages.value = navigator.languages;
8
+ };
9
+ window.addEventListener("languagechange", handler, { passive: !0 });
10
+ try {
11
+ onUnmounted(() => {
12
+ window.removeEventListener("languagechange", handler);
13
+ });
14
+ } catch {}
15
+ return languages;
16
+ }
@@ -0,0 +1,6 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Reactive preferred reduced motion.
4
+ */
5
+ export declare function usePreferredReducedMotion(): Ref<ReducedMotionType>;
6
+ export type ReducedMotionType = 'reduce' | 'no-preference';
@@ -0,0 +1,18 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ export function usePreferredReducedMotion() {
3
+ const motion = ref("no-preference");
4
+ if (typeof window > "u" || !window.matchMedia)
5
+ return motion;
6
+ const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
7
+ function update() {
8
+ motion.value = mq.matches ? "reduce" : "no-preference";
9
+ }
10
+ update();
11
+ mq.addEventListener("change", update);
12
+ try {
13
+ onUnmounted(() => {
14
+ mq.removeEventListener("change", update);
15
+ });
16
+ } catch {}
17
+ return motion;
18
+ }
@@ -0,0 +1,9 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Track the previous value of a ref.
4
+ * Returns a ref containing the value before the last change.
5
+ *
6
+ * @param value - The source ref to track
7
+ * @param initialValue - Optional initial value for the previous ref
8
+ */
9
+ export declare function usePrevious<T>(value: Ref<T>, initialValue?: T): Ref<T | undefined>;
@@ -0,0 +1,8 @@
1
+ import { ref, watch } from "@stacksjs/stx";
2
+ export function usePrevious(value, initialValue) {
3
+ const previous = ref(initialValue);
4
+ watch(value, (_newVal, oldVal) => {
5
+ previous.value = oldVal;
6
+ });
7
+ return previous;
8
+ }
@@ -0,0 +1,106 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ export declare function createQueryClient(options?: CreateQueryClientOptions): QueryClient;
3
+ /**
4
+ * Reactive query with cache + dedup + stale-while-revalidate.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * const judges = useQuery({
9
+ * queryKey: ['judges', { practiceArea: filter() }],
10
+ * queryFn: async ({ signal }) => {
11
+ * const res = await fetch('/api/judges', { signal })
12
+ * return res.json() as Promise<Judge[]>
13
+ * },
14
+ * staleTime: 30_000,
15
+ * })
16
+ * ```
17
+ */
18
+ export declare function useQuery<T>(opts: UseQueryOptions<T>): UseQueryResult<T>;
19
+ /**
20
+ * Reactive write-side primitive. Pairs with `useQuery` via
21
+ * `queryClient.invalidate(...)` inside `onSettled` for the canonical
22
+ * optimistic-with-rollback pattern.
23
+ */
24
+ export declare function useMutation<TData, TVars = void, TCtx = unknown>(opts: UseMutationOptions<TData, TVars, TCtx>): UseMutationResult<TData, TVars>;
25
+ /** Default app-wide client. Tests should pass their own via `client:`. */
26
+ export declare const queryClient: QueryClient;
27
+ declare interface CacheEntry<T = unknown> {
28
+ key: QueryKey
29
+ hash: string
30
+ data: T | undefined
31
+ error: Error | null
32
+ updatedAt: number
33
+ status: 'idle' | 'fetching' | 'success' | 'error'
34
+ inflight: Promise<T> | null
35
+ invalidated: boolean
36
+ subscribers: Set<() => unknown>
37
+ }
38
+ export declare interface CreateQueryClientOptions {
39
+ gcTime?: number
40
+ }
41
+ /**
42
+ * Central cache. Hold one per app (the default `queryClient` export)
43
+ * or create scoped ones for tests.
44
+ */
45
+ export declare interface QueryClient {
46
+ get: <T = unknown>(key: QueryKey) => T | undefined
47
+ set: <T = unknown>(key: QueryKey, value: T | ((old: T | undefined) => T)) => void
48
+ invalidate: (matcher: QueryMatcher) => Promise<void>
49
+ clear: () => void
50
+ gc: () => number
51
+ _subscribe: (hash: string, fn: () => unknown) => () => void
52
+ _entry: <T = unknown>(key: QueryKey) => CacheEntry<T>
53
+ _notify: (hash: string) => void
54
+ }
55
+ export declare interface UseQueryOptions<T> {
56
+ queryKey: QueryKey
57
+ queryFn: (ctx: { signal: AbortSignal }) => Promise<T>
58
+ staleTime?: number
59
+ enabled?: boolean
60
+ refetchOnFocus?: boolean
61
+ refetchOnReconnect?: boolean
62
+ window?: EventTarget
63
+ client?: QueryClient
64
+ }
65
+ export declare interface UseQueryResult<T> {
66
+ data: Ref<T | undefined>
67
+ error: Ref<Error | null>
68
+ isLoading: Ref<boolean>
69
+ isFetching: Ref<boolean>
70
+ refetch: () => Promise<void>
71
+ unsubscribe: () => void
72
+ }
73
+ export declare interface UseMutationOptions<TData, TVars, TCtx = unknown> {
74
+ mutationFn: (vars: TVars) => Promise<TData>
75
+ onMutate?: (vars: TVars) => Promise<TCtx> | TCtx
76
+ onSuccess?: (data: TData, vars: TVars, ctx: TCtx | undefined) => void | Promise<void>
77
+ onError?: (error: Error, vars: TVars, ctx: TCtx | undefined) => void | Promise<void>
78
+ onSettled?: (data: TData | undefined, error: Error | null, vars: TVars, ctx: TCtx | undefined) => void | Promise<void>
79
+ }
80
+ export declare interface UseMutationResult<TData, TVars> {
81
+ data: Ref<TData | undefined>
82
+ error: Ref<Error | null>
83
+ isPending: Ref<boolean>
84
+ mutate: (vars: TVars) => void
85
+ mutateAsync: (vars: TVars) => Promise<TData>
86
+ reset: () => void
87
+ }
88
+ /**
89
+ * useQuery / useMutation / queryClient (stacksjs/stacks#1939 — Phase A).
90
+ *
91
+ * Cache + dedup + invalidation primitives. Mirrors TanStack Query shape
92
+ * so adopters transfer immediately. Phase A intentionally omits:
93
+ * - `refetchOnFocus` / `refetchOnReconnect` (DOM listener coupling)
94
+ * - automatic GC of unsubscribed cache entries
95
+ * - query key partial-match invalidation via predicate functions
96
+ * Those land in Phase B. Prefix-match invalidation IS supported
97
+ * (`invalidate(['judges'])` matches `['judges', filterObj]` etc).
98
+ */
99
+ export type QueryKey = readonly unknown[];
100
+ /**
101
+ * Matcher for `invalidate`. Either a `QueryKey` (prefix match, the common
102
+ * case) or a predicate run against every cached key (stacksjs/stacks#1939
103
+ * Phase B) — e.g. invalidate everything tagged a given entity:
104
+ * `invalidate({ predicate: k => k.includes('judges') })`.
105
+ */
106
+ export type QueryMatcher = QueryKey | { predicate: (key: QueryKey) => boolean }
@@ -0,0 +1,265 @@
1
+ import { ref } from "@stacksjs/stx";
2
+ function stableStringify(value) {
3
+ if (value === null || typeof value !== "object")
4
+ return JSON.stringify(value);
5
+ if (Array.isArray(value))
6
+ return `[${value.map(stableStringify).join(",")}]`;
7
+ return `{${Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(",")}}`;
8
+ }
9
+ function hashKey(key) {
10
+ return stableStringify(key);
11
+ }
12
+ export function createQueryClient(options = {}) {
13
+ const entries = new Map, gcTime = options.gcTime ?? 300000, gcTimers = new Map;
14
+ function collectable(e) {
15
+ return e.subscribers.size === 0 && e.inflight === null;
16
+ }
17
+ function removeIfCollectable(hash) {
18
+ const e = entries.get(hash);
19
+ if (e && collectable(e))
20
+ entries.delete(hash);
21
+ gcTimers.delete(hash);
22
+ }
23
+ function scheduleGc(hash) {
24
+ const existing = gcTimers.get(hash);
25
+ if (existing)
26
+ clearTimeout(existing);
27
+ if (!Number.isFinite(gcTime))
28
+ return;
29
+ if (gcTime <= 0) {
30
+ removeIfCollectable(hash);
31
+ return;
32
+ }
33
+ const t = setTimeout(() => removeIfCollectable(hash), gcTime);
34
+ t.unref?.();
35
+ gcTimers.set(hash, t);
36
+ }
37
+ function cancelGc(hash) {
38
+ const t = gcTimers.get(hash);
39
+ if (t) {
40
+ clearTimeout(t);
41
+ gcTimers.delete(hash);
42
+ }
43
+ }
44
+ function entry(key) {
45
+ const hash = hashKey(key);
46
+ let e = entries.get(hash);
47
+ if (!e) {
48
+ e = {
49
+ key,
50
+ hash,
51
+ data: void 0,
52
+ error: null,
53
+ updatedAt: 0,
54
+ status: "idle",
55
+ inflight: null,
56
+ invalidated: !1,
57
+ subscribers: new Set
58
+ };
59
+ entries.set(hash, e);
60
+ }
61
+ return e;
62
+ }
63
+ function notify(hash) {
64
+ const e = entries.get(hash);
65
+ if (!e)
66
+ return;
67
+ for (const fn of e.subscribers)
68
+ fn();
69
+ }
70
+ function prefixMatches(prefix, candidate) {
71
+ if (prefix.length > candidate.length)
72
+ return !1;
73
+ for (let i = 0;i < prefix.length; i++)
74
+ if (stableStringify(prefix[i]) !== stableStringify(candidate[i]))
75
+ return !1;
76
+ return !0;
77
+ }
78
+ return {
79
+ get(key) {
80
+ const hash = hashKey(key);
81
+ return entries.get(hash)?.data;
82
+ },
83
+ set(key, value) {
84
+ const e = entry(key), next = typeof value === "function" ? value(e.data) : value;
85
+ e.data = next;
86
+ e.updatedAt = Date.now();
87
+ e.status = "success";
88
+ e.error = null;
89
+ e.invalidated = !1;
90
+ notify(e.hash);
91
+ },
92
+ async invalidate(matcher) {
93
+ const matches = Array.isArray(matcher) ? (key) => prefixMatches(matcher, key) : matcher.predicate, refetches = [];
94
+ for (const e of entries.values()) {
95
+ if (!matches(e.key))
96
+ continue;
97
+ e.updatedAt = 0;
98
+ e.invalidated = !0;
99
+ for (const fn of e.subscribers) {
100
+ const result = fn();
101
+ if (result && typeof result.then === "function")
102
+ refetches.push(result);
103
+ }
104
+ }
105
+ await Promise.all(refetches);
106
+ },
107
+ clear() {
108
+ for (const t of gcTimers.values())
109
+ clearTimeout(t);
110
+ gcTimers.clear();
111
+ entries.clear();
112
+ },
113
+ gc() {
114
+ let removed = 0;
115
+ for (const [hash, e] of entries)
116
+ if (collectable(e)) {
117
+ entries.delete(hash);
118
+ cancelGc(hash);
119
+ removed++;
120
+ }
121
+ return removed;
122
+ },
123
+ _subscribe(hash, fn) {
124
+ const e = entries.get(hash);
125
+ if (!e)
126
+ return () => {};
127
+ cancelGc(hash);
128
+ e.subscribers.add(fn);
129
+ return () => {
130
+ e.subscribers.delete(fn);
131
+ if (e.subscribers.size === 0)
132
+ scheduleGc(hash);
133
+ };
134
+ },
135
+ _entry: entry,
136
+ _notify: notify
137
+ };
138
+ }
139
+ export const queryClient = createQueryClient();
140
+ export function useQuery(opts) {
141
+ const client = opts.client ?? queryClient, staleTime = opts.staleTime ?? 0, enabled = opts.enabled ?? !0, e = client._entry(opts.queryKey), data = ref(e.data), error = ref(e.error), isLoading = ref(e.data === void 0 && enabled), isFetching = ref(!1);
142
+ function sync() {
143
+ data.value = e.data;
144
+ error.value = e.error;
145
+ isFetching.value = e.status === "fetching";
146
+ if (e.data !== void 0 || e.error !== null)
147
+ isLoading.value = !1;
148
+ }
149
+ async function doFetch(force) {
150
+ if (!force) {
151
+ if (e.data !== void 0 && Date.now() - e.updatedAt < staleTime) {
152
+ sync();
153
+ return;
154
+ }
155
+ }
156
+ if (e.inflight) {
157
+ try {
158
+ await e.inflight;
159
+ } catch {}
160
+ sync();
161
+ return;
162
+ }
163
+ const controller = new AbortController;
164
+ e.status = "fetching";
165
+ isFetching.value = !0;
166
+ if (e.data === void 0)
167
+ isLoading.value = !0;
168
+ const p = opts.queryFn({ signal: controller.signal }).then((result) => {
169
+ e.data = result;
170
+ e.error = null;
171
+ e.updatedAt = Date.now();
172
+ e.status = "success";
173
+ e.invalidated = !1;
174
+ return result;
175
+ }).catch((err) => {
176
+ e.error = err instanceof Error ? err : Error(String(err));
177
+ e.status = "error";
178
+ e.invalidated = !1;
179
+ throw e.error;
180
+ }).finally(() => {
181
+ e.inflight = null;
182
+ client._notify(e.hash);
183
+ });
184
+ e.inflight = p;
185
+ try {
186
+ await p;
187
+ } catch {}
188
+ sync();
189
+ }
190
+ const unsubscribeCache = client._subscribe(e.hash, () => {
191
+ if (e.invalidated && enabled && e.status !== "fetching")
192
+ return doFetch(!0);
193
+ sync();
194
+ return;
195
+ }), target = opts.window ?? (typeof window < "u" ? window : void 0), winListeners = [];
196
+ if (target && enabled) {
197
+ const onWake = () => {
198
+ if (e.status !== "fetching")
199
+ doFetch(!1);
200
+ };
201
+ if (opts.refetchOnFocus)
202
+ winListeners.push(["focus", onWake]);
203
+ if (opts.refetchOnReconnect)
204
+ winListeners.push(["online", onWake]);
205
+ for (const [evt, fn] of winListeners)
206
+ target.addEventListener(evt, fn);
207
+ }
208
+ function unsubscribe() {
209
+ unsubscribeCache();
210
+ if (target)
211
+ for (const [evt, fn] of winListeners)
212
+ target.removeEventListener(evt, fn);
213
+ }
214
+ if (enabled)
215
+ doFetch(!1);
216
+ else
217
+ sync();
218
+ return {
219
+ data,
220
+ error,
221
+ isLoading,
222
+ isFetching,
223
+ refetch: () => doFetch(!0),
224
+ unsubscribe
225
+ };
226
+ }
227
+ export function useMutation(opts) {
228
+ const data = ref(void 0), error = ref(null), isPending = ref(!1);
229
+ async function run(vars) {
230
+ isPending.value = !0;
231
+ error.value = null;
232
+ let ctx;
233
+ try {
234
+ if (opts.onMutate)
235
+ ctx = await opts.onMutate(vars);
236
+ const result = await opts.mutationFn(vars);
237
+ data.value = result;
238
+ await opts.onSuccess?.(result, vars, ctx);
239
+ await opts.onSettled?.(result, null, vars, ctx);
240
+ return result;
241
+ } catch (err) {
242
+ const e = err instanceof Error ? err : Error(String(err));
243
+ error.value = e;
244
+ await opts.onError?.(e, vars, ctx);
245
+ await opts.onSettled?.(void 0, e, vars, ctx);
246
+ throw e;
247
+ } finally {
248
+ isPending.value = !1;
249
+ }
250
+ }
251
+ return {
252
+ data,
253
+ error,
254
+ isPending,
255
+ mutate(vars) {
256
+ run(vars).catch(() => {});
257
+ },
258
+ mutateAsync: run,
259
+ reset() {
260
+ data.value = void 0;
261
+ error.value = null;
262
+ isPending.value = !1;
263
+ }
264
+ };
265
+ }
@@ -0,0 +1,19 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Call a function on every requestAnimationFrame.
4
+ * Provides pause/resume controls and auto-cleanup on unmount.
5
+ *
6
+ * @param fn - The callback invoked on each animation frame, receives { delta, timestamp }
7
+ * @param options - Configuration options (immediate defaults to true)
8
+ * @returns Controls to pause, resume, and check active state
9
+ */
10
+ export declare function useRafFn(fn: (args: UseRafFnCallbackArgs) => void, options?: { immediate?: boolean }): UseRafFnReturn;
11
+ declare interface UseRafFnCallbackArgs {
12
+ delta: number
13
+ timestamp: number
14
+ }
15
+ declare interface UseRafFnReturn {
16
+ pause: () => void
17
+ resume: () => void
18
+ isActive: Ref<boolean>
19
+ }
@@ -0,0 +1,37 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ export function useRafFn(fn, options = {}) {
3
+ const { immediate = !0 } = options, isActive = ref(!1);
4
+ let rafId = null, previousTimestamp = 0;
5
+ function loop(timestamp) {
6
+ if (!isActive.value)
7
+ return;
8
+ const delta = previousTimestamp ? timestamp - previousTimestamp : 0;
9
+ previousTimestamp = timestamp;
10
+ fn({ delta, timestamp });
11
+ rafId = requestAnimationFrame(loop);
12
+ }
13
+ function resume() {
14
+ if (isActive.value)
15
+ return;
16
+ if (typeof requestAnimationFrame > "u")
17
+ return;
18
+ isActive.value = !0;
19
+ previousTimestamp = 0;
20
+ rafId = requestAnimationFrame(loop);
21
+ }
22
+ function pause() {
23
+ if (!isActive.value)
24
+ return;
25
+ isActive.value = !1;
26
+ if (rafId !== null && typeof cancelAnimationFrame < "u") {
27
+ cancelAnimationFrame(rafId);
28
+ rafId = null;
29
+ }
30
+ }
31
+ if (immediate)
32
+ resume();
33
+ try {
34
+ onUnmounted(pause);
35
+ } catch {}
36
+ return { pause, resume, isActive };
37
+ }
@@ -0,0 +1,28 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Auto-tracked ref history with undo/redo.
4
+ * Automatically commits a snapshot on every change to the source ref.
5
+ *
6
+ * @param source - The reactive source to track
7
+ * @param options - Capacity limit, deep watching, and clone behavior
8
+ */
9
+ export declare function useRefHistory<T>(source: Ref<T>, options?: UseRefHistoryOptions): UseRefHistoryReturn<T>;
10
+ export declare interface UseRefHistoryRecord<T> {
11
+ snapshot: T
12
+ timestamp: number
13
+ }
14
+ export declare interface UseRefHistoryOptions {
15
+ capacity?: number
16
+ deep?: boolean
17
+ clone?: boolean
18
+ }
19
+ export declare interface UseRefHistoryReturn<T> {
20
+ history: Ref<UseRefHistoryRecord<T>[]>
21
+ commit: () => void
22
+ undo: () => void
23
+ redo: () => void
24
+ canUndo: Ref<boolean>
25
+ canRedo: Ref<boolean>
26
+ clear: () => void
27
+ last: Ref<UseRefHistoryRecord<T>>
28
+ }
@@ -0,0 +1,72 @@
1
+ import { computed, ref, watch } from "@stacksjs/stx";
2
+ function cloneValue(val, shouldClone) {
3
+ if (!shouldClone)
4
+ return val;
5
+ if (typeof structuredClone === "function")
6
+ return structuredClone(val);
7
+ return JSON.parse(JSON.stringify(val));
8
+ }
9
+ export function useRefHistory(source, options = {}) {
10
+ const { capacity = 1 / 0, deep = !1, clone = !1 } = options, undoStack = ref([
11
+ { snapshot: cloneValue(source.value, clone), timestamp: Date.now() }
12
+ ]), redoStack = ref([]);
13
+ let isUndoRedoing = !1;
14
+ const canUndo = computed(() => undoStack.value.length > 1), canRedo = computed(() => redoStack.value.length > 0), last = computed(() => {
15
+ return undoStack.value[undoStack.value.length - 1];
16
+ });
17
+ function commit() {
18
+ const record = {
19
+ snapshot: cloneValue(source.value, clone),
20
+ timestamp: Date.now()
21
+ };
22
+ undoStack.value = [...undoStack.value, record];
23
+ if (capacity !== 1 / 0 && undoStack.value.length > capacity)
24
+ undoStack.value = undoStack.value.slice(undoStack.value.length - capacity);
25
+ redoStack.value = [];
26
+ }
27
+ function undo() {
28
+ if (undoStack.value.length <= 1)
29
+ return;
30
+ isUndoRedoing = !0;
31
+ const current = undoStack.value[undoStack.value.length - 1], newUndoStack = undoStack.value.slice(0, -1);
32
+ undoStack.value = newUndoStack;
33
+ if (current)
34
+ redoStack.value = [...redoStack.value, current];
35
+ const previous = newUndoStack[newUndoStack.length - 1];
36
+ if (previous)
37
+ source.value = cloneValue(previous.snapshot, clone);
38
+ isUndoRedoing = !1;
39
+ }
40
+ function redo() {
41
+ if (redoStack.value.length === 0)
42
+ return;
43
+ isUndoRedoing = !0;
44
+ const next = redoStack.value[redoStack.value.length - 1];
45
+ redoStack.value = redoStack.value.slice(0, -1);
46
+ if (next) {
47
+ undoStack.value = [...undoStack.value, next];
48
+ source.value = cloneValue(next.snapshot, clone);
49
+ }
50
+ isUndoRedoing = !1;
51
+ }
52
+ function clear() {
53
+ undoStack.value = [
54
+ { snapshot: cloneValue(source.value, clone), timestamp: Date.now() }
55
+ ];
56
+ redoStack.value = [];
57
+ }
58
+ watch(source, () => {
59
+ if (!isUndoRedoing)
60
+ commit();
61
+ }, { deep });
62
+ return {
63
+ history: undoStack,
64
+ commit,
65
+ undo,
66
+ redo,
67
+ canUndo,
68
+ canRedo,
69
+ clear,
70
+ last
71
+ };
72
+ }
@@ -0,0 +1,16 @@
1
+ import { type MaybeRef } from './_shared';
2
+ import type { Ref } from '@stacksjs/stx';
3
+ /**
4
+ * Reactive ResizeObserver.
5
+ * Observes the target element and calls the callback when the element is resized.
6
+ *
7
+ * @param target - The element to observe (or a Ref to one)
8
+ * @param callback - ResizeObserverCallback
9
+ * @param options - ResizeObserverOptions
10
+ * @returns isSupported ref and stop function
11
+ */
12
+ export declare function useResizeObserver(target: MaybeRef<HTMLElement | null>, callback: ResizeObserverCallback, options?: ResizeObserverOptions): UseResizeObserverReturn;
13
+ export declare interface UseResizeObserverReturn {
14
+ isSupported: Ref<boolean>
15
+ stop: () => void
16
+ }
@@ -0,0 +1,27 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ import { unref, noop } from "./_shared";
3
+ export function useResizeObserver(target, callback, options) {
4
+ const isSupported = ref(typeof window < "u" && "ResizeObserver" in window);
5
+ let cleanup = noop;
6
+ (() => {
7
+ cleanup();
8
+ if (!isSupported.value)
9
+ return;
10
+ const el = unref(target);
11
+ if (!el)
12
+ return;
13
+ const observer = new ResizeObserver(callback);
14
+ observer.observe(el, options);
15
+ cleanup = () => {
16
+ observer.disconnect();
17
+ cleanup = noop;
18
+ };
19
+ })();
20
+ const stop = () => {
21
+ cleanup();
22
+ };
23
+ try {
24
+ onUnmounted(stop);
25
+ } catch {}
26
+ return { isSupported, stop };
27
+ }
@@ -0,0 +1,13 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Reactive Screen Orientation API.
4
+ */
5
+ export declare function useScreenOrientation(): UseScreenOrientationReturn;
6
+ export declare interface UseScreenOrientationReturn {
7
+ isSupported: Ref<boolean>
8
+ orientation: Ref<string | undefined>
9
+ angle: Ref<number>
10
+ lockOrientation: (type: ScreenOrientationLockType) => Promise<void>
11
+ unlockOrientation: () => void
12
+ }
13
+ declare type ScreenOrientationLockType = 'any' | 'natural' | 'landscape' | 'portrait' | 'portrait-primary' | 'portrait-secondary' | 'landscape-primary' | 'landscape-secondary';