@stacksjs/composables 0.70.88 → 0.70.90

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,182 @@
1
+ import { ref } from "@stacksjs/stx";
2
+ export function useForm(opts) {
3
+ const validateOn = opts.validateOn ?? "submit", initial = { ...opts.initialValues }, values = ref({ ...initial }), errors = ref({}), touched = ref({}), dirty = ref({}), isSubmitting = ref(!1), isValid = ref(!0), isDirty = ref(!1);
4
+ function firstMessage(result) {
5
+ if (result.valid)
6
+ return "";
7
+ if (Array.isArray(result.errors))
8
+ return result.errors[0]?.message ?? "Invalid";
9
+ for (const list of Object.values(result.errors))
10
+ if (list.length > 0)
11
+ return list[0]?.message ?? "Invalid";
12
+ return "Invalid";
13
+ }
14
+ function validateField(name) {
15
+ const v = opts.schema?.[name];
16
+ if (!v)
17
+ return !0;
18
+ const result = v.validate(values.value[name]), message = firstMessage(result);
19
+ if (message) {
20
+ errors.value = { ...errors.value, [name]: message };
21
+ isValid.value = !1;
22
+ return !1;
23
+ }
24
+ if (errors.value[name]) {
25
+ const { [name]: _, ...rest } = errors.value;
26
+ errors.value = rest;
27
+ }
28
+ isValid.value = Object.keys(errors.value).length === 0;
29
+ return !0;
30
+ }
31
+ function setFieldValue(name, value) {
32
+ values.value = { ...values.value, [name]: value };
33
+ dirty.value = { ...dirty.value, [name]: value !== initial[name] };
34
+ isDirty.value = !0;
35
+ if (validateOn === "change")
36
+ validateField(name);
37
+ }
38
+ function setFieldTouched(name, isTouched = !0) {
39
+ touched.value = { ...touched.value, [name]: isTouched };
40
+ if (isTouched)
41
+ isDirty.value = !0;
42
+ }
43
+ function field(name) {
44
+ const key = name, errorId = `${key}-error`, onBlur = () => {
45
+ setFieldTouched(name, !0);
46
+ if (validateOn === "blur" || validateOn === "change")
47
+ validateField(name);
48
+ };
49
+ return {
50
+ get value() {
51
+ return values.value[name];
52
+ },
53
+ get error() {
54
+ return errors.value[key] ?? "";
55
+ },
56
+ get touched() {
57
+ return !!touched.value[key];
58
+ },
59
+ get dirty() {
60
+ return !!dirty.value[key];
61
+ },
62
+ errorId,
63
+ setValue: (next) => setFieldValue(name, next),
64
+ onBlur,
65
+ validate: () => validateField(name),
66
+ inputProps: () => {
67
+ const hasError = !!errors.value[key];
68
+ return {
69
+ name: key,
70
+ value: values.value[name],
71
+ onInput: (eventOrValue) => {
72
+ const next = eventOrValue && typeof eventOrValue === "object" && "target" in eventOrValue ? eventOrValue.target.value : eventOrValue;
73
+ setFieldValue(name, next);
74
+ },
75
+ onBlur,
76
+ "aria-invalid": hasError,
77
+ "aria-describedby": hasError ? errorId : void 0
78
+ };
79
+ }
80
+ };
81
+ }
82
+ function validateAll() {
83
+ let ok = !0;
84
+ for (const name of Object.keys(opts.schema ?? {}))
85
+ if (!validateField(name))
86
+ ok = !1;
87
+ return ok;
88
+ }
89
+ function setError(name, message) {
90
+ errors.value = { ...errors.value, [name]: message };
91
+ isValid.value = !1;
92
+ }
93
+ function setErrors(errorMap) {
94
+ const next = { ...errors.value };
95
+ let changed = !1;
96
+ const list = Object.entries(errorMap);
97
+ for (const [key, msg] of list) {
98
+ if (msg == null)
99
+ continue;
100
+ const message = Array.isArray(msg) ? msg[0] : msg;
101
+ if (message == null || message === "")
102
+ continue;
103
+ next[key] = message;
104
+ changed = !0;
105
+ }
106
+ errors.value = next;
107
+ if (changed)
108
+ isValid.value = !1;
109
+ }
110
+ function clearErrors(name) {
111
+ if (name == null) {
112
+ errors.value = {};
113
+ isValid.value = !0;
114
+ return;
115
+ }
116
+ const { [name]: _, ...rest } = errors.value;
117
+ errors.value = rest;
118
+ isValid.value = Object.keys(errors.value).length === 0;
119
+ }
120
+ async function handleSubmit() {
121
+ const allTouched = {};
122
+ for (const k of Object.keys(values.value))
123
+ allTouched[k] = !0;
124
+ touched.value = allTouched;
125
+ if (!validateAll()) {
126
+ opts.onError?.(errors.value);
127
+ return;
128
+ }
129
+ isSubmitting.value = !0;
130
+ try {
131
+ await opts.onSubmit(values.value);
132
+ } catch (err) {
133
+ const e = err instanceof Error ? err : Error(String(err));
134
+ setError("form", e.message);
135
+ opts.onError?.(e);
136
+ } finally {
137
+ isSubmitting.value = !1;
138
+ }
139
+ }
140
+ function reset() {
141
+ values.value = { ...initial };
142
+ errors.value = {};
143
+ touched.value = {};
144
+ dirty.value = {};
145
+ isSubmitting.value = !1;
146
+ isValid.value = !0;
147
+ isDirty.value = !1;
148
+ }
149
+ function submitButtonProps() {
150
+ return {
151
+ type: "submit",
152
+ disabled: isSubmitting.value,
153
+ "aria-busy": isSubmitting.value
154
+ };
155
+ }
156
+ function firstErrorField() {
157
+ for (const k of Object.keys(initial))
158
+ if (errors.value[k])
159
+ return k;
160
+ return null;
161
+ }
162
+ return {
163
+ values,
164
+ errors,
165
+ touched,
166
+ dirty,
167
+ isSubmitting,
168
+ isValid,
169
+ isDirty,
170
+ field,
171
+ setValue: setFieldValue,
172
+ setError,
173
+ setErrors,
174
+ clearErrors,
175
+ setTouched: setFieldTouched,
176
+ validate: validateAll,
177
+ handleSubmit,
178
+ reset,
179
+ submitButtonProps,
180
+ firstErrorField
181
+ };
182
+ }
@@ -0,0 +1,7 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Reactive FPS (frames per second) counter.
4
+ *
5
+ * @param every - How many frames between updates. Default: 10
6
+ */
7
+ export declare function useFps(every?: number): Ref<number>;
package/dist/useFps.js ADDED
@@ -0,0 +1,22 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ export function useFps(every = 10) {
3
+ const fps = ref(0);
4
+ if (typeof requestAnimationFrame > "u")
5
+ return fps;
6
+ let last = performance.now(), ticks = 0, rafId;
7
+ function loop() {
8
+ ticks++;
9
+ if (ticks >= every) {
10
+ const now = performance.now(), diff = now - last;
11
+ fps.value = Math.round(ticks / diff * 1000);
12
+ last = now;
13
+ ticks = 0;
14
+ }
15
+ rafId = requestAnimationFrame(loop);
16
+ }
17
+ rafId = requestAnimationFrame(loop);
18
+ try {
19
+ onUnmounted(() => cancelAnimationFrame(rafId));
20
+ } catch {}
21
+ return fps;
22
+ }
@@ -0,0 +1,16 @@
1
+ import type { MaybeRef } from './_shared';
2
+ import type { Ref } from '@stacksjs/stx';
3
+ /**
4
+ * Reactive Fullscreen API.
5
+ * Enter, exit, and toggle fullscreen mode on an element.
6
+ *
7
+ * @param target - Target element (defaults to documentElement)
8
+ */
9
+ export declare function useFullscreen(target?: MaybeRef<HTMLElement | null>): UseFullscreenReturn;
10
+ export declare interface UseFullscreenReturn {
11
+ isFullscreen: Ref<boolean>
12
+ isSupported: Ref<boolean>
13
+ enter: () => Promise<void>
14
+ exit: () => Promise<void>
15
+ toggle: () => Promise<void>
16
+ }
@@ -0,0 +1,67 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ import { defaultDocument, unref } from "./_shared";
3
+ export function useFullscreen(target) {
4
+ const doc = defaultDocument(), isFullscreen = ref(!1), isSupported = ref(!!doc && (("fullscreenEnabled" in doc) || ("webkitFullscreenEnabled" in doc)));
5
+ function getTarget() {
6
+ if (target)
7
+ return unref(target);
8
+ return doc?.documentElement ?? null;
9
+ }
10
+ function getFullscreenElement() {
11
+ if (!doc)
12
+ return null;
13
+ return doc.fullscreenElement ?? doc.webkitFullscreenElement ?? null;
14
+ }
15
+ function updateState() {
16
+ isFullscreen.value = getFullscreenElement() !== null;
17
+ }
18
+ async function enter() {
19
+ if (!isSupported.value)
20
+ return;
21
+ const el = getTarget();
22
+ if (!el)
23
+ return;
24
+ try {
25
+ if (el.requestFullscreen)
26
+ await el.requestFullscreen();
27
+ else if (el.webkitRequestFullscreen)
28
+ await el.webkitRequestFullscreen();
29
+ isFullscreen.value = !0;
30
+ } catch {}
31
+ }
32
+ async function exit() {
33
+ if (!isSupported.value || !doc)
34
+ return;
35
+ try {
36
+ if (doc.exitFullscreen)
37
+ await doc.exitFullscreen();
38
+ else if (doc.webkitExitFullscreen)
39
+ await doc.webkitExitFullscreen();
40
+ isFullscreen.value = !1;
41
+ } catch {}
42
+ }
43
+ async function toggle() {
44
+ if (isFullscreen.value)
45
+ await exit();
46
+ else
47
+ await enter();
48
+ }
49
+ if (doc) {
50
+ const handler = () => updateState();
51
+ doc.addEventListener("fullscreenchange", handler);
52
+ doc.addEventListener("webkitfullscreenchange", handler);
53
+ try {
54
+ onUnmounted(() => {
55
+ doc.removeEventListener("fullscreenchange", handler);
56
+ doc.removeEventListener("webkitfullscreenchange", handler);
57
+ });
58
+ } catch {}
59
+ }
60
+ return {
61
+ isFullscreen,
62
+ isSupported,
63
+ enter,
64
+ exit,
65
+ toggle
66
+ };
67
+ }
@@ -0,0 +1,26 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Reactive geolocation.
4
+ * Tracks the user's geographic position using the Geolocation API.
5
+ *
6
+ * @param options - PositionOptions plus an immediate flag (default: true)
7
+ * @returns Reactive coords, location timestamp, error, support status, and pause/resume controls
8
+ */
9
+ export declare function useGeolocation(options?: PositionOptions & { immediate?: boolean }): UseGeolocationReturn;
10
+ export declare interface UseGeolocationCoords {
11
+ latitude: Ref<number | null>
12
+ longitude: Ref<number | null>
13
+ accuracy: Ref<number | null>
14
+ altitude: Ref<number | null>
15
+ altitudeAccuracy: Ref<number | null>
16
+ heading: Ref<number | null>
17
+ speed: Ref<number | null>
18
+ }
19
+ export declare interface UseGeolocationReturn {
20
+ coords: UseGeolocationCoords
21
+ locatedAt: Ref<number | null>
22
+ error: Ref<GeolocationPositionError | null>
23
+ isSupported: Ref<boolean>
24
+ pause: () => void
25
+ resume: () => void
26
+ }
@@ -0,0 +1,55 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ import { noop } from "./_shared";
3
+ export function useGeolocation(options) {
4
+ const { immediate = !0, ...positionOptions } = options ?? {}, isSupported = ref(typeof navigator < "u" && "geolocation" in navigator), coords = {
5
+ latitude: ref(null),
6
+ longitude: ref(null),
7
+ accuracy: ref(null),
8
+ altitude: ref(null),
9
+ altitudeAccuracy: ref(null),
10
+ heading: ref(null),
11
+ speed: ref(null)
12
+ }, locatedAt = ref(null), error = ref(null);
13
+ let watchId = null, cleanup = noop;
14
+ const updatePosition = (position) => {
15
+ coords.latitude.value = position.coords.latitude;
16
+ coords.longitude.value = position.coords.longitude;
17
+ coords.accuracy.value = position.coords.accuracy;
18
+ coords.altitude.value = position.coords.altitude;
19
+ coords.altitudeAccuracy.value = position.coords.altitudeAccuracy;
20
+ coords.heading.value = position.coords.heading;
21
+ coords.speed.value = position.coords.speed;
22
+ locatedAt.value = position.timestamp;
23
+ error.value = null;
24
+ }, onError = (err) => {
25
+ error.value = err;
26
+ }, resume = () => {
27
+ if (!isSupported.value)
28
+ return;
29
+ if (watchId !== null)
30
+ return;
31
+ watchId = navigator.geolocation.watchPosition(updatePosition, onError, positionOptions);
32
+ cleanup = () => {
33
+ if (watchId !== null) {
34
+ navigator.geolocation.clearWatch(watchId);
35
+ watchId = null;
36
+ }
37
+ cleanup = noop;
38
+ };
39
+ }, pause = () => {
40
+ cleanup();
41
+ };
42
+ if (immediate)
43
+ resume();
44
+ try {
45
+ onUnmounted(pause);
46
+ } catch {}
47
+ return {
48
+ coords,
49
+ locatedAt,
50
+ error,
51
+ isSupported,
52
+ pause,
53
+ resume
54
+ };
55
+ }
@@ -0,0 +1,18 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * User idle detection.
4
+ * Tracks whether the user is idle based on activity events.
5
+ *
6
+ * @param timeout - Idle timeout in milliseconds. Default: 60000 (1 minute)
7
+ * @param options - Configuration for events and initial state
8
+ * @returns Reactive idle state and last active timestamp
9
+ */
10
+ export declare function useIdle(timeout?: number, options?: UseIdleOptions): UseIdleReturn;
11
+ export declare interface UseIdleOptions {
12
+ events?: string[]
13
+ initialState?: boolean
14
+ }
15
+ export declare interface UseIdleReturn {
16
+ idle: Ref<boolean>
17
+ lastActive: Ref<number>
18
+ }
@@ -0,0 +1,46 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ import { noop } from "./_shared";
3
+ const DEFAULT_EVENTS = [
4
+ "mousemove",
5
+ "mousedown",
6
+ "resize",
7
+ "keydown",
8
+ "touchstart",
9
+ "wheel"
10
+ ];
11
+ export function useIdle(timeout = 60000, options) {
12
+ const events = options?.events ?? DEFAULT_EVENTS, initialState = options?.initialState ?? !1, idle = ref(initialState), lastActive = ref(Date.now());
13
+ let timer = null, cleanup = noop;
14
+ if (typeof window < "u") {
15
+ const cleanups = [], reset = () => {
16
+ idle.value = !1;
17
+ lastActive.value = Date.now();
18
+ if (timer !== null)
19
+ clearTimeout(timer);
20
+ timer = setTimeout(() => {
21
+ idle.value = !0;
22
+ }, timeout);
23
+ };
24
+ for (const event of events) {
25
+ window.addEventListener(event, reset, { passive: !0 });
26
+ cleanups.push(() => window.removeEventListener(event, reset));
27
+ }
28
+ timer = setTimeout(() => {
29
+ idle.value = !0;
30
+ }, timeout);
31
+ cleanup = () => {
32
+ for (const fn of cleanups)
33
+ fn();
34
+ cleanups.length = 0;
35
+ if (timer !== null) {
36
+ clearTimeout(timer);
37
+ timer = null;
38
+ }
39
+ cleanup = noop;
40
+ };
41
+ }
42
+ try {
43
+ onUnmounted(() => cleanup());
44
+ } catch {}
45
+ return { idle, lastActive };
46
+ }
@@ -0,0 +1,18 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Reactive image loading state.
4
+ */
5
+ export declare function useImage(options: UseImageOptions): UseImageReturn;
6
+ export declare interface UseImageOptions {
7
+ src: string
8
+ srcset?: string
9
+ sizes?: string
10
+ alt?: string
11
+ crossorigin?: string
12
+ referrerpolicy?: string
13
+ }
14
+ export declare interface UseImageReturn {
15
+ isLoading: Ref<boolean>
16
+ error: Ref<string | null>
17
+ isReady: Ref<boolean>
18
+ }
@@ -0,0 +1,32 @@
1
+ import { ref } from "@stacksjs/stx";
2
+ export function useImage(options) {
3
+ const isLoading = ref(!0), isReady = ref(!1), error = ref(null);
4
+ if (typeof Image > "u") {
5
+ isLoading.value = !1;
6
+ return { isLoading, error, isReady };
7
+ }
8
+ const img = new Image;
9
+ img.onload = () => {
10
+ isLoading.value = !1;
11
+ isReady.value = !0;
12
+ };
13
+ img.onerror = (e) => {
14
+ isLoading.value = !1;
15
+ if (typeof e === "string")
16
+ error.value = e;
17
+ else if (e instanceof Event && e.type === "error")
18
+ error.value = `Failed to load image: ${options.src}`;
19
+ else
20
+ error.value = "Failed to load image";
21
+ };
22
+ if (options.crossorigin)
23
+ img.crossOrigin = options.crossorigin;
24
+ if (options.referrerpolicy)
25
+ img.referrerPolicy = options.referrerpolicy;
26
+ if (options.sizes)
27
+ img.sizes = options.sizes;
28
+ if (options.srcset)
29
+ img.srcset = options.srcset;
30
+ img.src = options.src;
31
+ return { isLoading, error, isReady };
32
+ }
@@ -0,0 +1,11 @@
1
+ import type { MaybeRef } from './_shared';
2
+ import type { Ref } from '@stacksjs/stx';
3
+ /**
4
+ * Infinite scroll detection.
5
+ * Calls the `onLoadMore` callback when the user scrolls near the edge.
6
+ */
7
+ export declare function useInfiniteScroll(target: MaybeRef<HTMLElement | Window | null | undefined>, onLoadMore: () => void | Promise<void>, options?: UseInfiniteScrollOptions): { isLoading: Ref<boolean> };
8
+ export declare interface UseInfiniteScrollOptions {
9
+ distance?: number
10
+ direction?: 'top' | 'bottom' | 'left' | 'right'
11
+ }
@@ -0,0 +1,50 @@
1
+ import { onUnmounted, ref, watch } from "@stacksjs/stx";
2
+ import { unref } from "./_shared";
3
+ export function useInfiniteScroll(target, onLoadMore, options = {}) {
4
+ const { distance = 100, direction = "bottom" } = options, isLoading = ref(!1);
5
+ let active = !0;
6
+ const handler = async () => {
7
+ if (!active || isLoading.value)
8
+ return;
9
+ const el = unref(target);
10
+ if (!el)
11
+ return;
12
+ let shouldLoad = !1;
13
+ if (el === window || el === document.documentElement) {
14
+ const scrollTop = window.scrollY || document.documentElement.scrollTop, scrollHeight = document.documentElement.scrollHeight, clientHeight = window.innerHeight;
15
+ if (direction === "bottom")
16
+ shouldLoad = scrollHeight - scrollTop - clientHeight <= distance;
17
+ else if (direction === "top")
18
+ shouldLoad = scrollTop <= distance;
19
+ } else {
20
+ const element = el;
21
+ if (direction === "bottom")
22
+ shouldLoad = element.scrollHeight - element.scrollTop - element.clientHeight <= distance;
23
+ else if (direction === "top")
24
+ shouldLoad = element.scrollTop <= distance;
25
+ else if (direction === "right")
26
+ shouldLoad = element.scrollWidth - element.scrollLeft - element.clientWidth <= distance;
27
+ else if (direction === "left")
28
+ shouldLoad = element.scrollLeft <= distance;
29
+ }
30
+ if (shouldLoad) {
31
+ isLoading.value = !0;
32
+ try {
33
+ await onLoadMore();
34
+ } finally {
35
+ isLoading.value = !1;
36
+ }
37
+ }
38
+ }, el = unref(target);
39
+ if (el) {
40
+ const scrollTarget = el === document.documentElement ? window : el;
41
+ scrollTarget.addEventListener("scroll", handler, { passive: !0 });
42
+ try {
43
+ onUnmounted(() => {
44
+ active = !1;
45
+ scrollTarget.removeEventListener("scroll", handler);
46
+ });
47
+ } catch {}
48
+ }
49
+ return { isLoading };
50
+ }
@@ -0,0 +1,16 @@
1
+ import { type MaybeRef } from './_shared';
2
+ import type { Ref } from '@stacksjs/stx';
3
+ /**
4
+ * Reactive IntersectionObserver.
5
+ * Observes the target element and calls the callback when intersection changes.
6
+ *
7
+ * @param target - The element to observe (or a Ref to one)
8
+ * @param callback - IntersectionObserverCallback
9
+ * @param options - IntersectionObserverInit options
10
+ * @returns isSupported ref and stop function
11
+ */
12
+ export declare function useIntersectionObserver(target: MaybeRef<HTMLElement | null>, callback: IntersectionObserverCallback, options?: IntersectionObserverInit): UseIntersectionObserverReturn;
13
+ export declare interface UseIntersectionObserverReturn {
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 useIntersectionObserver(target, callback, options) {
4
+ const isSupported = ref(typeof window < "u" && "IntersectionObserver" 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 IntersectionObserver(callback, options);
14
+ observer.observe(el);
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
+ export declare function useInterval(interval?: number, options?: { controls?: false, immediate?: boolean }): Ref<number>;
3
+ export declare function useInterval(interval?: number, options?: UseIntervalOptions): Ref<number> | UseIntervalControls;
4
+ declare interface UseIntervalControls {
5
+ counter: Ref<number>
6
+ pause: () => void
7
+ resume: () => void
8
+ reset: () => void
9
+ }
10
+ declare interface UseIntervalOptions {
11
+ controls?: boolean
12
+ immediate?: boolean
13
+ }
@@ -0,0 +1,32 @@
1
+ import { onUnmounted, ref } from "@stacksjs/stx";
2
+ export function useInterval(interval = 1000, options = {}) {
3
+ const { controls = !1, immediate = !0 } = options, counter = ref(0);
4
+ let intervalId = null;
5
+ function pause() {
6
+ if (intervalId !== null) {
7
+ clearInterval(intervalId);
8
+ intervalId = null;
9
+ }
10
+ }
11
+ function resume() {
12
+ if (intervalId !== null)
13
+ return;
14
+ intervalId = setInterval(() => {
15
+ counter.value++;
16
+ }, interval);
17
+ }
18
+ function reset() {
19
+ counter.value = 0;
20
+ pause();
21
+ if (immediate)
22
+ resume();
23
+ }
24
+ if (immediate)
25
+ resume();
26
+ try {
27
+ onUnmounted(pause);
28
+ } catch {}
29
+ if (controls)
30
+ return { counter, pause, resume, reset };
31
+ return counter;
32
+ }
@@ -0,0 +1,16 @@
1
+ import type { Ref } from '@stacksjs/stx';
2
+ /**
3
+ * Call a function on a regular interval.
4
+ * Provides pause/resume controls and auto-cleanup on unmount.
5
+ *
6
+ * @param cb - The callback to invoke on each interval tick
7
+ * @param interval - Interval duration in milliseconds (default 1000)
8
+ * @param options - Configuration options
9
+ * @returns Controls to pause, resume, and check active state
10
+ */
11
+ export declare function useIntervalFn(cb: () => void, interval?: number, options?: { immediate?: boolean }): UseIntervalFnReturn;
12
+ declare interface UseIntervalFnReturn {
13
+ pause: () => void
14
+ resume: () => void
15
+ isActive: Ref<boolean>
16
+ }