@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.
- package/dist/_shared.d.ts +49 -0
- package/dist/_shared.js +23 -0
- package/dist/cloneFnJSON.d.ts +5 -0
- package/dist/cloneFnJSON.js +3 -0
- package/dist/computedAsync.d.ts +28 -0
- package/dist/computedAsync.js +20 -0
- package/dist/computedEager.d.ts +27 -0
- package/dist/computedEager.js +10 -0
- package/dist/createEventHook.d.ts +16 -0
- package/dist/createEventHook.js +15 -0
- package/dist/createFetch.d.ts +14 -0
- package/dist/createFetch.js +8 -0
- package/dist/createGlobalState.d.ts +17 -0
- package/dist/createGlobalState.js +10 -0
- package/dist/createSharedComposable.d.ts +8 -0
- package/dist/createSharedComposable.js +9 -0
- package/dist/extendRef.d.ts +9 -0
- package/dist/extendRef.js +6 -0
- package/dist/formatTimeAgo.d.ts +23 -0
- package/dist/formatTimeAgo.js +33 -0
- package/dist/index.d.ts +271 -0
- package/dist/index.js +210 -0
- package/dist/isDefined.d.ts +5 -0
- package/dist/isDefined.js +3 -0
- package/dist/makeDestructurable.d.ts +18 -0
- package/dist/makeDestructurable.js +16 -0
- package/dist/onClickOutside.d.ts +14 -0
- package/dist/onClickOutside.js +25 -0
- package/dist/onKeyStroke.d.ts +26 -0
- package/dist/onKeyStroke.js +31 -0
- package/dist/onLongPress.d.ts +14 -0
- package/dist/onLongPress.js +43 -0
- package/dist/onStartTyping.d.ts +8 -0
- package/dist/onStartTyping.js +23 -0
- package/dist/refAutoReset.d.ts +11 -0
- package/dist/refAutoReset.js +15 -0
- package/dist/refDefault.d.ts +9 -0
- package/dist/refDefault.js +8 -0
- package/dist/resolveRef.d.ts +7 -0
- package/dist/resolveRef.js +7 -0
- package/dist/ssrHandlers.d.ts +13 -0
- package/dist/ssrHandlers.js +8 -0
- package/dist/syncRef.d.ts +21 -0
- package/dist/syncRef.js +35 -0
- package/dist/tryOnMounted.d.ts +22 -0
- package/dist/tryOnMounted.js +22 -0
- package/dist/unrefElement.d.ts +6 -0
- package/dist/unrefElement.js +9 -0
- package/dist/until.d.ts +34 -0
- package/dist/until.js +62 -0
- package/dist/useActiveElement.d.ts +6 -0
- package/dist/useActiveElement.js +19 -0
- package/dist/useAnimate.d.ts +18 -0
- package/dist/useAnimate.js +48 -0
- package/dist/useArrayUtils.d.ts +42 -0
- package/dist/useArrayUtils.js +114 -0
- package/dist/useAsyncQueue.d.ts +18 -0
- package/dist/useAsyncQueue.js +22 -0
- package/dist/useAsyncState.d.ts +23 -0
- package/dist/useAsyncState.js +35 -0
- package/dist/useBase64.d.ts +12 -0
- package/dist/useBase64.js +45 -0
- package/dist/useBattery.d.ts +15 -0
- package/dist/useBattery.js +38 -0
- package/dist/useBreakpoints.d.ts +96 -0
- package/dist/useBreakpoints.js +97 -0
- package/dist/useBroadcastChannel.d.ts +14 -0
- package/dist/useBroadcastChannel.js +31 -0
- package/dist/useBrowserLocation.d.ts +18 -0
- package/dist/useBrowserLocation.js +64 -0
- package/dist/useClipboard.d.ts +17 -0
- package/dist/useClipboard.js +32 -0
- package/dist/useClipboardItems.d.ts +11 -0
- package/dist/useClipboardItems.js +15 -0
- package/dist/useCloned.d.ts +15 -0
- package/dist/useCloned.js +16 -0
- package/dist/useColorMode.d.ts +18 -0
- package/dist/useColorMode.js +60 -0
- package/dist/useConfirmDialog.d.ts +14 -0
- package/dist/useConfirmDialog.js +34 -0
- package/dist/useCounter.d.ts +20 -0
- package/dist/useCounter.js +28 -0
- package/dist/useCssVar.d.ts +10 -0
- package/dist/useCssVar.js +23 -0
- package/dist/useCycleList.d.ts +18 -0
- package/dist/useCycleList.js +27 -0
- package/dist/useDark.d.ts +11 -0
- package/dist/useDark.js +38 -0
- package/dist/useDateFormat.d.ts +10 -0
- package/dist/useDateFormat.js +11 -0
- package/dist/useDebounce.d.ts +10 -0
- package/dist/useDebounce.js +16 -0
- package/dist/useDebounceFn.d.ts +10 -0
- package/dist/useDebounceFn.js +18 -0
- package/dist/useDebouncedRef.d.ts +11 -0
- package/dist/useDebouncedRef.js +22 -0
- package/dist/useDebouncedRefHistory.d.ts +5 -0
- package/dist/useDebouncedRefHistory.js +36 -0
- package/dist/useDeviceMotion.d.ts +27 -0
- package/dist/useDeviceMotion.js +53 -0
- package/dist/useDeviceOrientation.d.ts +15 -0
- package/dist/useDeviceOrientation.js +23 -0
- package/dist/useDevicePixelRatio.d.ts +5 -0
- package/dist/useDevicePixelRatio.js +24 -0
- package/dist/useDocumentVisibility.d.ts +5 -0
- package/dist/useDocumentVisibility.js +16 -0
- package/dist/useDraggable.d.ts +23 -0
- package/dist/useDraggable.js +58 -0
- package/dist/useDropZone.d.ts +15 -0
- package/dist/useDropZone.js +52 -0
- package/dist/useElementBounding.d.ts +21 -0
- package/dist/useElementBounding.js +59 -0
- package/dist/useElementByPoint.d.ts +10 -0
- package/dist/useElementByPoint.js +18 -0
- package/dist/useElementHover.d.ts +9 -0
- package/dist/useElementHover.js +28 -0
- package/dist/useElementSize.d.ts +19 -0
- package/dist/useElementSize.js +34 -0
- package/dist/useElementVisibility.d.ts +10 -0
- package/dist/useElementVisibility.js +10 -0
- package/dist/useEventBus.d.ts +14 -0
- package/dist/useEventBus.js +41 -0
- package/dist/useEventListener.d.ts +14 -0
- package/dist/useEventListener.js +29 -0
- package/dist/useEventSource.d.ts +32 -0
- package/dist/useEventSource.js +72 -0
- package/dist/useEyeDropper.d.ts +10 -0
- package/dist/useEyeDropper.js +17 -0
- package/dist/useFavicon.d.ts +8 -0
- package/dist/useFavicon.js +22 -0
- package/dist/useFetch.d.ts +35 -0
- package/dist/useFetch.js +61 -0
- package/dist/useFileDialog.d.ts +15 -0
- package/dist/useFileDialog.js +24 -0
- package/dist/useFocus.d.ts +13 -0
- package/dist/useFocus.js +42 -0
- package/dist/useFocusWithin.d.ts +9 -0
- package/dist/useFocusWithin.js +29 -0
- package/dist/useForm.d.ts +97 -0
- package/dist/useForm.js +182 -0
- package/dist/useFps.d.ts +7 -0
- package/dist/useFps.js +22 -0
- package/dist/useFullscreen.d.ts +16 -0
- package/dist/useFullscreen.js +67 -0
- package/dist/useGeolocation.d.ts +26 -0
- package/dist/useGeolocation.js +55 -0
- package/dist/useIdle.d.ts +18 -0
- package/dist/useIdle.js +46 -0
- package/dist/useImage.d.ts +18 -0
- package/dist/useImage.js +32 -0
- package/dist/useInfiniteScroll.d.ts +11 -0
- package/dist/useInfiniteScroll.js +50 -0
- package/dist/useIntersectionObserver.d.ts +16 -0
- package/dist/useIntersectionObserver.js +27 -0
- package/dist/useInterval.d.ts +13 -0
- package/dist/useInterval.js +32 -0
- package/dist/useIntervalFn.d.ts +16 -0
- package/dist/useIntervalFn.js +24 -0
- package/dist/useKeyModifier.d.ts +6 -0
- package/dist/useKeyModifier.js +22 -0
- package/dist/useLastChanged.d.ts +11 -0
- package/dist/useLastChanged.js +8 -0
- package/dist/useLocalStorage.d.ts +17 -0
- package/dist/useLocalStorage.js +4 -0
- package/dist/useMagicKeys.d.ts +16 -0
- package/dist/useMagicKeys.js +81 -0
- package/dist/useManualRefHistory.d.ts +27 -0
- package/dist/useManualRefHistory.js +64 -0
- package/dist/useMath.d.ts +17 -0
- package/dist/useMath.js +52 -0
- package/dist/useMediaQuery.d.ts +9 -0
- package/dist/useMediaQuery.js +19 -0
- package/dist/useMemoize.d.ts +13 -0
- package/dist/useMemoize.js +24 -0
- package/dist/useMounted.d.ts +6 -0
- package/dist/useMounted.js +8 -0
- package/dist/useMouse.d.ts +19 -0
- package/dist/useMouse.js +67 -0
- package/dist/useMouseInElement.d.ts +17 -0
- package/dist/useMouseInElement.js +31 -0
- package/dist/useMousePressed.d.ts +10 -0
- package/dist/useMousePressed.js +31 -0
- package/dist/useMutationObserver.d.ts +16 -0
- package/dist/useMutationObserver.js +27 -0
- package/dist/useNavigatorLanguage.d.ts +5 -0
- package/dist/useNavigatorLanguage.js +17 -0
- package/dist/useNetwork.d.ts +18 -0
- package/dist/useNetwork.js +58 -0
- package/dist/useNow.d.ts +8 -0
- package/dist/useNow.js +10 -0
- package/dist/useObjectUrl.d.ts +8 -0
- package/dist/useObjectUrl.js +23 -0
- package/dist/useOffsetPagination.d.ts +21 -0
- package/dist/useOffsetPagination.js +45 -0
- package/dist/useOnline.d.ts +7 -0
- package/dist/useOnline.js +20 -0
- package/dist/usePageLeave.d.ts +9 -0
- package/dist/usePageLeave.js +27 -0
- package/dist/useParallax.d.ts +15 -0
- package/dist/useParallax.js +33 -0
- package/dist/useParentElement.d.ts +6 -0
- package/dist/useParentElement.js +8 -0
- package/dist/usePermission.d.ts +7 -0
- package/dist/usePermission.js +21 -0
- package/dist/usePointer.d.ts +15 -0
- package/dist/usePointer.js +32 -0
- package/dist/usePointerLock.d.ts +13 -0
- package/dist/usePointerLock.js +33 -0
- package/dist/usePointerSwipe.d.ts +20 -0
- package/dist/usePointerSwipe.js +52 -0
- package/dist/usePreferredColorScheme.d.ts +6 -0
- package/dist/usePreferredColorScheme.js +25 -0
- package/dist/usePreferredContrast.d.ts +6 -0
- package/dist/usePreferredContrast.js +29 -0
- package/dist/usePreferredLanguages.d.ts +5 -0
- package/dist/usePreferredLanguages.js +16 -0
- package/dist/usePreferredReducedMotion.d.ts +6 -0
- package/dist/usePreferredReducedMotion.js +18 -0
- package/dist/usePrevious.d.ts +9 -0
- package/dist/usePrevious.js +8 -0
- package/dist/useQuery.d.ts +106 -0
- package/dist/useQuery.js +265 -0
- package/dist/useRafFn.d.ts +19 -0
- package/dist/useRafFn.js +37 -0
- package/dist/useRefHistory.d.ts +28 -0
- package/dist/useRefHistory.js +72 -0
- package/dist/useResizeObserver.d.ts +16 -0
- package/dist/useResizeObserver.js +27 -0
- package/dist/useScreenOrientation.d.ts +13 -0
- package/dist/useScreenOrientation.js +27 -0
- package/dist/useScreenSafeArea.d.ts +12 -0
- package/dist/useScreenSafeArea.js +25 -0
- package/dist/useScriptTag.d.ts +20 -0
- package/dist/useScriptTag.js +52 -0
- package/dist/useScroll.d.ts +36 -0
- package/dist/useScroll.js +116 -0
- package/dist/useScrollLock.d.ts +10 -0
- package/dist/useScrollLock.js +39 -0
- package/dist/useSessionStorage.d.ts +17 -0
- package/dist/useSessionStorage.js +4 -0
- package/dist/useShare.d.ts +15 -0
- package/dist/useShare.js +11 -0
- package/dist/useSorted.d.ts +10 -0
- package/dist/useSorted.js +10 -0
- package/dist/useStepper.d.ts +23 -0
- package/dist/useStepper.js +46 -0
- package/dist/useStorage.d.ts +18 -0
- package/dist/useStorage.js +54 -0
- package/dist/useStyleTag.d.ts +17 -0
- package/dist/useStyleTag.js +39 -0
- package/dist/useSupported.d.ts +8 -0
- package/dist/useSupported.js +10 -0
- package/dist/useSwipe.d.ts +20 -0
- package/dist/useSwipe.js +58 -0
- package/dist/useTextDirection.d.ts +9 -0
- package/dist/useTextDirection.js +16 -0
- package/dist/useTextSelection.d.ts +10 -0
- package/dist/useTextSelection.js +27 -0
- package/dist/useTextareaAutosize.d.ts +10 -0
- package/dist/useTextareaAutosize.js +20 -0
- package/dist/useThrottle.d.ts +9 -0
- package/dist/useThrottle.js +23 -0
- package/dist/useThrottleFn.d.ts +11 -0
- package/dist/useThrottleFn.js +36 -0
- package/dist/useThrottledRef.d.ts +11 -0
- package/dist/useThrottledRef.js +30 -0
- package/dist/useThrottledRefHistory.d.ts +5 -0
- package/dist/useThrottledRefHistory.js +43 -0
- package/dist/useTimeAgo.d.ts +16 -0
- package/dist/useTimeAgo.js +58 -0
- package/dist/useTimeout.d.ts +12 -0
- package/dist/useTimeout.js +32 -0
- package/dist/useTimeoutFn.d.ts +16 -0
- package/dist/useTimeoutFn.js +27 -0
- package/dist/useTimeoutPoll.d.ts +10 -0
- package/dist/useTimeoutPoll.js +33 -0
- package/dist/useTimestamp.d.ts +15 -0
- package/dist/useTimestamp.js +43 -0
- package/dist/useTitle.d.ts +10 -0
- package/dist/useTitle.js +12 -0
- package/dist/useToNumber.d.ts +11 -0
- package/dist/useToNumber.js +25 -0
- package/dist/useToString.d.ts +6 -0
- package/dist/useToString.js +10 -0
- package/dist/useToggle.d.ts +6 -0
- package/dist/useToggle.js +12 -0
- package/dist/useTransition.d.ts +28 -0
- package/dist/useTransition.js +89 -0
- package/dist/useUrlSearchParams.d.ts +18 -0
- package/dist/useUrlSearchParams.js +72 -0
- package/dist/useVibrate.d.ts +13 -0
- package/dist/useVibrate.js +14 -0
- package/dist/useVirtualList.d.ts +23 -0
- package/dist/useVirtualList.js +49 -0
- package/dist/useWakeLock.d.ts +12 -0
- package/dist/useWakeLock.js +32 -0
- package/dist/useWebNotification.d.ts +25 -0
- package/dist/useWebNotification.js +39 -0
- package/dist/useWebSocket.d.ts +38 -0
- package/dist/useWebSocket.js +103 -0
- package/dist/useWebWorker.d.ts +18 -0
- package/dist/useWebWorker.js +56 -0
- package/dist/useWindowFocus.d.ts +5 -0
- package/dist/useWindowFocus.js +20 -0
- package/dist/useWindowScroll.d.ts +9 -0
- package/dist/useWindowScroll.js +17 -0
- package/dist/useWindowSize.d.ts +15 -0
- package/dist/useWindowSize.js +28 -0
- package/dist/watchArray.d.ts +5 -0
- package/dist/watchArray.js +9 -0
- package/dist/watchAtMost.d.ts +5 -0
- package/dist/watchAtMost.js +12 -0
- package/dist/watchDebounced.d.ts +23 -0
- package/dist/watchDebounced.js +20 -0
- package/dist/watchDeep.d.ts +7 -0
- package/dist/watchDeep.js +13 -0
- package/dist/watchIgnorable.d.ts +12 -0
- package/dist/watchIgnorable.js +19 -0
- package/dist/watchImmediate.d.ts +5 -0
- package/dist/watchImmediate.js +7 -0
- package/dist/watchOnce.d.ts +19 -0
- package/dist/watchOnce.js +17 -0
- package/dist/watchPausable.d.ts +13 -0
- package/dist/watchPausable.js +23 -0
- package/dist/watchThrottled.d.ts +23 -0
- package/dist/watchThrottled.js +37 -0
- package/dist/watchTriggerable.d.ts +5 -0
- package/dist/watchTriggerable.js +10 -0
- package/dist/watchWithFilter.d.ts +7 -0
- package/dist/watchWithFilter.js +6 -0
- package/dist/whenever.d.ts +18 -0
- package/dist/whenever.js +7 -0
- package/package.json +2 -2
package/dist/useForm.js
ADDED
|
@@ -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
|
+
}
|
package/dist/useFps.d.ts
ADDED
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
|
+
}
|
package/dist/useIdle.js
ADDED
|
@@ -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
|
+
}
|
package/dist/useImage.js
ADDED
|
@@ -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
|
+
}
|