@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.
- 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
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { onUnmounted, ref } from "@stacksjs/stx";
|
|
2
|
+
import { unref, noop } from "./_shared";
|
|
3
|
+
export function useElementSize(target, options) {
|
|
4
|
+
const width = ref(options?.initialSize?.width ?? 0), height = ref(options?.initialSize?.height ?? 0), isSupported = typeof window < "u" && "ResizeObserver" in window;
|
|
5
|
+
let cleanup = noop;
|
|
6
|
+
if (isSupported) {
|
|
7
|
+
const el = unref(target);
|
|
8
|
+
if (el) {
|
|
9
|
+
const observer = new ResizeObserver((entries) => {
|
|
10
|
+
for (const entry of entries)
|
|
11
|
+
if (entry.contentBoxSize) {
|
|
12
|
+
const boxSize = Array.isArray(entry.contentBoxSize) ? entry.contentBoxSize[0] : entry.contentBoxSize;
|
|
13
|
+
width.value = boxSize.inlineSize;
|
|
14
|
+
height.value = boxSize.blockSize;
|
|
15
|
+
} else {
|
|
16
|
+
width.value = entry.contentRect.width;
|
|
17
|
+
height.value = entry.contentRect.height;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
observer.observe(el);
|
|
21
|
+
cleanup = () => {
|
|
22
|
+
observer.disconnect();
|
|
23
|
+
cleanup = noop;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const stop = () => {
|
|
28
|
+
cleanup();
|
|
29
|
+
};
|
|
30
|
+
try {
|
|
31
|
+
onUnmounted(stop);
|
|
32
|
+
} catch {}
|
|
33
|
+
return { width, height, stop };
|
|
34
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type MaybeRef } from './_shared';
|
|
2
|
+
import type { Ref } from '@stacksjs/stx';
|
|
3
|
+
/**
|
|
4
|
+
* Reactive element visibility.
|
|
5
|
+
* Uses IntersectionObserver to track whether the target element is visible in the viewport.
|
|
6
|
+
*
|
|
7
|
+
* @param target - The element to observe (or a Ref to one)
|
|
8
|
+
* @returns A ref that is true when the element is visible
|
|
9
|
+
*/
|
|
10
|
+
export declare function useElementVisibility(target: MaybeRef<HTMLElement | null>): Ref<boolean>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ref } from "@stacksjs/stx";
|
|
2
|
+
import { useIntersectionObserver } from "./useIntersectionObserver";
|
|
3
|
+
export function useElementVisibility(target) {
|
|
4
|
+
const isVisible = ref(!1);
|
|
5
|
+
useIntersectionObserver(target, (entries) => {
|
|
6
|
+
for (const entry of entries)
|
|
7
|
+
isVisible.value = entry.isIntersecting;
|
|
8
|
+
}, { threshold: 0 });
|
|
9
|
+
return isVisible;
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A reactive event bus for cross-component communication.
|
|
3
|
+
*
|
|
4
|
+
* @param key - A unique key identifying the event bus channel
|
|
5
|
+
*/
|
|
6
|
+
export declare function useEventBus<T = any>(key: string | symbol): UseEventBusReturn<T>;
|
|
7
|
+
export declare interface UseEventBusReturn<T = any> {
|
|
8
|
+
on: (listener: EventBusListener<T>) => () => void
|
|
9
|
+
once: (listener: EventBusListener<T>) => () => void
|
|
10
|
+
emit: (event: T) => void
|
|
11
|
+
off: (listener: EventBusListener<T>) => void
|
|
12
|
+
reset: () => void
|
|
13
|
+
}
|
|
14
|
+
export type EventBusListener<T = any> = (_event: T) => void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { onUnmounted } from "@stacksjs/stx";
|
|
2
|
+
const buses = new Map;
|
|
3
|
+
export function useEventBus(key) {
|
|
4
|
+
if (!buses.has(key))
|
|
5
|
+
buses.set(key, new Set);
|
|
6
|
+
const listeners = buses.get(key), localListeners = [];
|
|
7
|
+
function on(listener) {
|
|
8
|
+
listeners.add(listener);
|
|
9
|
+
localListeners.push(listener);
|
|
10
|
+
return () => off(listener);
|
|
11
|
+
}
|
|
12
|
+
function once(listener) {
|
|
13
|
+
const wrapper = (event) => {
|
|
14
|
+
listener(event);
|
|
15
|
+
off(wrapper);
|
|
16
|
+
};
|
|
17
|
+
return on(wrapper);
|
|
18
|
+
}
|
|
19
|
+
function emit(event) {
|
|
20
|
+
for (const listener of listeners)
|
|
21
|
+
listener(event);
|
|
22
|
+
}
|
|
23
|
+
function off(listener) {
|
|
24
|
+
listeners.delete(listener);
|
|
25
|
+
const idx = localListeners.indexOf(listener);
|
|
26
|
+
if (idx !== -1)
|
|
27
|
+
localListeners.splice(idx, 1);
|
|
28
|
+
}
|
|
29
|
+
function reset() {
|
|
30
|
+
listeners.clear();
|
|
31
|
+
localListeners.length = 0;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
onUnmounted(() => {
|
|
35
|
+
for (const listener of localListeners)
|
|
36
|
+
listeners.delete(listener);
|
|
37
|
+
localListeners.length = 0;
|
|
38
|
+
});
|
|
39
|
+
} catch {}
|
|
40
|
+
return { on, once, emit, off, reset };
|
|
41
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type MaybeRef } from './_shared';
|
|
2
|
+
/**
|
|
3
|
+
* Auto-cleanup event listener.
|
|
4
|
+
* Registers an event listener on the target and automatically removes it on unmount.
|
|
5
|
+
* Supports reactive targets via MaybeRef.
|
|
6
|
+
*
|
|
7
|
+
* @param target - The event target (Window, Document, HTMLElement, or a Ref to one)
|
|
8
|
+
* @param event - The event name
|
|
9
|
+
* @param handler - The event handler
|
|
10
|
+
* @param options - AddEventListenerOptions
|
|
11
|
+
* @returns A cleanup function to manually remove the listener
|
|
12
|
+
*/
|
|
13
|
+
export declare function useEventListener(target: MaybeRef<EventTarget | null | undefined> | EventTarget, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): () => void;
|
|
14
|
+
declare type EventTarget = Window | Document | HTMLElement | Element;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { onUnmounted, watch } from "@stacksjs/stx";
|
|
2
|
+
import { isRef, unref, noop, defaultWindow } from "./_shared";
|
|
3
|
+
export function useEventListener(target, event, handler, options) {
|
|
4
|
+
let cleanup = noop;
|
|
5
|
+
const register = (el) => {
|
|
6
|
+
if (!el)
|
|
7
|
+
return noop;
|
|
8
|
+
el.addEventListener(event, handler, options);
|
|
9
|
+
return () => {
|
|
10
|
+
el.removeEventListener(event, handler, options);
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
if (isRef(target)) {
|
|
14
|
+
watch(target, (_newTarget, _oldTarget) => {
|
|
15
|
+
cleanup();
|
|
16
|
+
cleanup = register(unref(target));
|
|
17
|
+
});
|
|
18
|
+
cleanup = register(target.value);
|
|
19
|
+
} else
|
|
20
|
+
cleanup = register(target);
|
|
21
|
+
const stop = () => {
|
|
22
|
+
cleanup();
|
|
23
|
+
cleanup = noop;
|
|
24
|
+
};
|
|
25
|
+
try {
|
|
26
|
+
onUnmounted(stop);
|
|
27
|
+
} catch {}
|
|
28
|
+
return stop;
|
|
29
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { MaybeRefOrGetter } from './_shared';
|
|
2
|
+
import type { Ref } from '@stacksjs/stx';
|
|
3
|
+
/**
|
|
4
|
+
* Reactive Server-Sent Events (EventSource) connection.
|
|
5
|
+
*
|
|
6
|
+
* @param url - The EventSource URL (can be a ref, getter, or raw string)
|
|
7
|
+
* @param events - Array of event names to listen for (in addition to 'message')
|
|
8
|
+
* @param options - Configuration options
|
|
9
|
+
* @returns Reactive EventSource state and control methods
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const { data, event, status, close } = useEventSource('/api/events', ['update', 'delete'], {
|
|
14
|
+
* withCredentials: true,
|
|
15
|
+
* })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function useEventSource(url: MaybeRefOrGetter<string>, events?: string[], options?: UseEventSourceOptions): UseEventSourceReturn;
|
|
19
|
+
export declare interface UseEventSourceOptions {
|
|
20
|
+
withCredentials?: boolean
|
|
21
|
+
immediate?: boolean
|
|
22
|
+
}
|
|
23
|
+
export declare interface UseEventSourceReturn {
|
|
24
|
+
data: Ref<string | null>
|
|
25
|
+
event: Ref<string | null>
|
|
26
|
+
status: Ref<EventSourceStatus>
|
|
27
|
+
error: Ref<Event | null>
|
|
28
|
+
eventSource: Ref<EventSource | null>
|
|
29
|
+
close: () => void
|
|
30
|
+
open: () => void
|
|
31
|
+
}
|
|
32
|
+
export type EventSourceStatus = 'CONNECTING' | 'OPEN' | 'CLOSED';
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { onUnmounted, ref } from "@stacksjs/stx";
|
|
2
|
+
import { toValue } from "./_shared";
|
|
3
|
+
export function useEventSource(url, events = [], options = {}) {
|
|
4
|
+
const {
|
|
5
|
+
withCredentials = !1,
|
|
6
|
+
immediate = !0
|
|
7
|
+
} = options, data = ref(null), event = ref(null), status = ref("CLOSED"), error = ref(null), eventSourceRef = ref(null);
|
|
8
|
+
let listeners = [];
|
|
9
|
+
function close() {
|
|
10
|
+
const es = eventSourceRef.value;
|
|
11
|
+
if (es) {
|
|
12
|
+
for (const { eventName, handler } of listeners)
|
|
13
|
+
es.removeEventListener(eventName, handler);
|
|
14
|
+
listeners = [];
|
|
15
|
+
es.close();
|
|
16
|
+
eventSourceRef.value = null;
|
|
17
|
+
status.value = "CLOSED";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function open() {
|
|
21
|
+
if (typeof EventSource > "u")
|
|
22
|
+
return;
|
|
23
|
+
close();
|
|
24
|
+
const resolvedUrl = toValue(url);
|
|
25
|
+
status.value = "CONNECTING";
|
|
26
|
+
const es = new EventSource(resolvedUrl, { withCredentials });
|
|
27
|
+
eventSourceRef.value = es;
|
|
28
|
+
es.onopen = () => {
|
|
29
|
+
status.value = "OPEN";
|
|
30
|
+
error.value = null;
|
|
31
|
+
};
|
|
32
|
+
es.onerror = (e) => {
|
|
33
|
+
error.value = e;
|
|
34
|
+
if (es.readyState === EventSource.CLOSED)
|
|
35
|
+
status.value = "CLOSED";
|
|
36
|
+
else
|
|
37
|
+
status.value = "CONNECTING";
|
|
38
|
+
};
|
|
39
|
+
const messageHandler = (e) => {
|
|
40
|
+
const messageEvent = e;
|
|
41
|
+
data.value = messageEvent.data;
|
|
42
|
+
event.value = "message";
|
|
43
|
+
};
|
|
44
|
+
es.addEventListener("message", messageHandler);
|
|
45
|
+
listeners.push({ eventName: "message", handler: messageHandler });
|
|
46
|
+
for (const eventName of events) {
|
|
47
|
+
const handler = (e) => {
|
|
48
|
+
const messageEvent = e;
|
|
49
|
+
data.value = messageEvent.data;
|
|
50
|
+
event.value = eventName;
|
|
51
|
+
};
|
|
52
|
+
es.addEventListener(eventName, handler);
|
|
53
|
+
listeners.push({ eventName, handler });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (immediate)
|
|
57
|
+
open();
|
|
58
|
+
try {
|
|
59
|
+
onUnmounted(() => {
|
|
60
|
+
close();
|
|
61
|
+
});
|
|
62
|
+
} catch {}
|
|
63
|
+
return {
|
|
64
|
+
data,
|
|
65
|
+
event,
|
|
66
|
+
status,
|
|
67
|
+
error,
|
|
68
|
+
eventSource: eventSourceRef,
|
|
69
|
+
close,
|
|
70
|
+
open
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
/**
|
|
3
|
+
* Reactive EyeDropper API.
|
|
4
|
+
*/
|
|
5
|
+
export declare function useEyeDropper(): UseEyeDropperReturn;
|
|
6
|
+
export declare interface UseEyeDropperReturn {
|
|
7
|
+
isSupported: Ref<boolean>
|
|
8
|
+
sRGBHex: Ref<string>
|
|
9
|
+
open: () => Promise<{ sRGBHex: string } | undefined>
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ref } from "@stacksjs/stx";
|
|
2
|
+
export function useEyeDropper() {
|
|
3
|
+
const isSupported = ref(typeof window < "u" && "EyeDropper" in window), sRGBHex = ref("");
|
|
4
|
+
async function open() {
|
|
5
|
+
if (!isSupported.value)
|
|
6
|
+
return;
|
|
7
|
+
const dropper = new window.EyeDropper;
|
|
8
|
+
try {
|
|
9
|
+
const result = await dropper.open();
|
|
10
|
+
sRGBHex.value = result.sRGBHex;
|
|
11
|
+
return result;
|
|
12
|
+
} catch {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return { isSupported, sRGBHex, open };
|
|
17
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MaybeRefOrGetter } from './_shared';
|
|
2
|
+
import type { Ref } from '@stacksjs/stx';
|
|
3
|
+
/**
|
|
4
|
+
* Reactive favicon.
|
|
5
|
+
*
|
|
6
|
+
* @param newIcon - URL of the favicon or a reactive ref/getter
|
|
7
|
+
*/
|
|
8
|
+
export declare function useFavicon(newIcon?: MaybeRefOrGetter<string | null | undefined>): Ref<string | null>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ref, watch } from "@stacksjs/stx";
|
|
2
|
+
import { toValue } from "./_shared";
|
|
3
|
+
export function useFavicon(newIcon) {
|
|
4
|
+
const favicon = ref(toValue(newIcon ?? null));
|
|
5
|
+
function applyIcon(icon) {
|
|
6
|
+
if (typeof document > "u" || !icon)
|
|
7
|
+
return;
|
|
8
|
+
let link = document.querySelector('link[rel*="icon"]');
|
|
9
|
+
if (!link) {
|
|
10
|
+
link = document.createElement("link");
|
|
11
|
+
link.rel = "icon";
|
|
12
|
+
link.type = "image/x-icon";
|
|
13
|
+
document.head.appendChild(link);
|
|
14
|
+
}
|
|
15
|
+
link.href = icon;
|
|
16
|
+
}
|
|
17
|
+
watch(favicon, (val) => {
|
|
18
|
+
applyIcon(val);
|
|
19
|
+
});
|
|
20
|
+
applyIcon(favicon.value);
|
|
21
|
+
return favicon;
|
|
22
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
/**
|
|
3
|
+
* Chainable reactive fetch composable. Pass the expected success body
|
|
4
|
+
* shape as the type argument to get a typed `data.value`.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* interface Post { id: number, title: string }
|
|
9
|
+
* const { error, data } = await useFetch<Post[]>('/api/posts').get().json()
|
|
10
|
+
* // data: Ref<Post[] | null>
|
|
11
|
+
* const { data } = await useFetch<Post>('/api/posts').post(JSON.stringify(body)).json()
|
|
12
|
+
* const { error } = await useFetch('/api/posts/1').delete().json()
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function useFetch<T = unknown>(url: string): FetchBuilder<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Result of a terminal `.json()` call. Generic over the success body
|
|
18
|
+
* `T` (stacksjs/stacks#1924) so `data.value` is typed instead of
|
|
19
|
+
* `any`. `error` stays `unknown` — it can be a parsed error body OR a
|
|
20
|
+
* thrown network error, so the caller should narrow before use.
|
|
21
|
+
*/
|
|
22
|
+
export declare interface UseFetchResult<T = unknown> {
|
|
23
|
+
data: Ref<T | null>
|
|
24
|
+
error: Ref<unknown>
|
|
25
|
+
isFetching: Ref<boolean>
|
|
26
|
+
then: (resolve: (value: { data: Ref<T | null>, error: Ref<unknown> }) => void) => Promise<void>
|
|
27
|
+
}
|
|
28
|
+
export declare interface FetchBuilder<T = unknown> {
|
|
29
|
+
get: () => FetchBuilder<T>
|
|
30
|
+
post: (body?: string) => FetchBuilder<T>
|
|
31
|
+
patch: (body?: string) => FetchBuilder<T>
|
|
32
|
+
put: (body?: string) => FetchBuilder<T>
|
|
33
|
+
delete: () => FetchBuilder<T>
|
|
34
|
+
json: () => UseFetchResult<T>
|
|
35
|
+
}
|
package/dist/useFetch.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ref } from "@stacksjs/stx";
|
|
2
|
+
export function useFetch(url) {
|
|
3
|
+
let method = "GET", body;
|
|
4
|
+
const builder = {
|
|
5
|
+
get() {
|
|
6
|
+
method = "GET";
|
|
7
|
+
body = void 0;
|
|
8
|
+
return builder;
|
|
9
|
+
},
|
|
10
|
+
post(b) {
|
|
11
|
+
method = "POST";
|
|
12
|
+
body = b;
|
|
13
|
+
return builder;
|
|
14
|
+
},
|
|
15
|
+
patch(b) {
|
|
16
|
+
method = "PATCH";
|
|
17
|
+
body = b;
|
|
18
|
+
return builder;
|
|
19
|
+
},
|
|
20
|
+
put(b) {
|
|
21
|
+
method = "PUT";
|
|
22
|
+
body = b;
|
|
23
|
+
return builder;
|
|
24
|
+
},
|
|
25
|
+
delete() {
|
|
26
|
+
method = "DELETE";
|
|
27
|
+
body = void 0;
|
|
28
|
+
return builder;
|
|
29
|
+
},
|
|
30
|
+
json() {
|
|
31
|
+
const data = ref(null), error = ref(null), isFetching = ref(!0), init = {
|
|
32
|
+
method,
|
|
33
|
+
headers: { Accept: "application/json" }
|
|
34
|
+
};
|
|
35
|
+
if (body && method !== "GET" && method !== "DELETE") {
|
|
36
|
+
init.headers = { ...init.headers, "Content-Type": "application/json" };
|
|
37
|
+
init.body = body;
|
|
38
|
+
}
|
|
39
|
+
const result = { data, error }, fetchPromise = fetch(url, init).then(async (response) => {
|
|
40
|
+
const json = await response.json();
|
|
41
|
+
if (response.ok)
|
|
42
|
+
data.value = json;
|
|
43
|
+
else
|
|
44
|
+
error.value = json;
|
|
45
|
+
}).catch((e) => {
|
|
46
|
+
error.value = e;
|
|
47
|
+
}).finally(() => {
|
|
48
|
+
isFetching.value = !1;
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
data,
|
|
52
|
+
error,
|
|
53
|
+
isFetching,
|
|
54
|
+
then(resolve) {
|
|
55
|
+
return fetchPromise.then(() => resolve(result));
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return builder;
|
|
61
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
/**
|
|
3
|
+
* Open a file selection dialog programmatically.
|
|
4
|
+
*/
|
|
5
|
+
export declare function useFileDialog(options?: UseFileDialogOptions): UseFileDialogReturn;
|
|
6
|
+
export declare interface UseFileDialogOptions {
|
|
7
|
+
accept?: string
|
|
8
|
+
multiple?: boolean
|
|
9
|
+
capture?: string
|
|
10
|
+
}
|
|
11
|
+
export declare interface UseFileDialogReturn {
|
|
12
|
+
files: Ref<FileList | null>
|
|
13
|
+
open: (options?: UseFileDialogOptions) => void
|
|
14
|
+
reset: () => void
|
|
15
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ref } from "@stacksjs/stx";
|
|
2
|
+
export function useFileDialog(options = {}) {
|
|
3
|
+
const files = ref(null);
|
|
4
|
+
function open(overrideOptions) {
|
|
5
|
+
if (typeof document > "u")
|
|
6
|
+
return;
|
|
7
|
+
const opts = { ...options, ...overrideOptions }, input = document.createElement("input");
|
|
8
|
+
input.type = "file";
|
|
9
|
+
if (opts.accept)
|
|
10
|
+
input.accept = opts.accept;
|
|
11
|
+
if (opts.multiple)
|
|
12
|
+
input.multiple = !0;
|
|
13
|
+
if (opts.capture)
|
|
14
|
+
input.setAttribute("capture", opts.capture);
|
|
15
|
+
input.onchange = () => {
|
|
16
|
+
files.value = input.files;
|
|
17
|
+
};
|
|
18
|
+
input.click();
|
|
19
|
+
}
|
|
20
|
+
function reset() {
|
|
21
|
+
files.value = null;
|
|
22
|
+
}
|
|
23
|
+
return { files, open, reset };
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MaybeRef } from './_shared';
|
|
2
|
+
import type { Ref } from '@stacksjs/stx';
|
|
3
|
+
/**
|
|
4
|
+
* Reactive element focus state.
|
|
5
|
+
* Setting `focused.value = true` will focus the element, and vice versa.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useFocus(target: MaybeRef<HTMLElement | null | undefined>, options?: UseFocusOptions): UseFocusReturn;
|
|
8
|
+
export declare interface UseFocusOptions {
|
|
9
|
+
initialValue?: boolean
|
|
10
|
+
}
|
|
11
|
+
export declare interface UseFocusReturn {
|
|
12
|
+
focused: Ref<boolean>
|
|
13
|
+
}
|
package/dist/useFocus.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { onUnmounted, ref, watch } from "@stacksjs/stx";
|
|
2
|
+
import { unref } from "./_shared";
|
|
3
|
+
export function useFocus(target, options = {}) {
|
|
4
|
+
const { initialValue = !1 } = options, focused = ref(initialValue);
|
|
5
|
+
let cleanup = () => {};
|
|
6
|
+
function setup(el) {
|
|
7
|
+
cleanup();
|
|
8
|
+
if (!el)
|
|
9
|
+
return;
|
|
10
|
+
const onFocus = () => {
|
|
11
|
+
focused.value = !0;
|
|
12
|
+
}, onBlur = () => {
|
|
13
|
+
focused.value = !1;
|
|
14
|
+
};
|
|
15
|
+
el.addEventListener("focus", onFocus, { passive: !0 });
|
|
16
|
+
el.addEventListener("blur", onBlur, { passive: !0 });
|
|
17
|
+
cleanup = () => {
|
|
18
|
+
el.removeEventListener("focus", onFocus);
|
|
19
|
+
el.removeEventListener("blur", onBlur);
|
|
20
|
+
cleanup = () => {};
|
|
21
|
+
};
|
|
22
|
+
if (document.activeElement === el)
|
|
23
|
+
focused.value = !0;
|
|
24
|
+
if (initialValue)
|
|
25
|
+
el.focus();
|
|
26
|
+
}
|
|
27
|
+
const el = unref(target);
|
|
28
|
+
setup(el);
|
|
29
|
+
watch(focused, (val) => {
|
|
30
|
+
const element = unref(target);
|
|
31
|
+
if (!element)
|
|
32
|
+
return;
|
|
33
|
+
if (val)
|
|
34
|
+
element.focus();
|
|
35
|
+
else
|
|
36
|
+
element.blur();
|
|
37
|
+
});
|
|
38
|
+
try {
|
|
39
|
+
onUnmounted(() => cleanup());
|
|
40
|
+
} catch {}
|
|
41
|
+
return { focused };
|
|
42
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MaybeRef } from './_shared';
|
|
2
|
+
import type { Ref } from '@stacksjs/stx';
|
|
3
|
+
/**
|
|
4
|
+
* Reactive state of whether focus is contained within the target element.
|
|
5
|
+
*
|
|
6
|
+
* @param target - The target element or a ref to one
|
|
7
|
+
* @returns focused - true when focus is within the element or its descendants
|
|
8
|
+
*/
|
|
9
|
+
export declare function useFocusWithin(target: MaybeRef<HTMLElement | null | undefined>): { focused: Ref<boolean> };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { onUnmounted, ref } from "@stacksjs/stx";
|
|
2
|
+
import { unref } from "./_shared";
|
|
3
|
+
export function useFocusWithin(target) {
|
|
4
|
+
const focused = ref(!1);
|
|
5
|
+
let cleanup = () => {};
|
|
6
|
+
function setup(el) {
|
|
7
|
+
cleanup();
|
|
8
|
+
if (!el)
|
|
9
|
+
return;
|
|
10
|
+
const onFocusIn = () => {
|
|
11
|
+
focused.value = !0;
|
|
12
|
+
}, onFocusOut = (e) => {
|
|
13
|
+
if (!el.contains(e.relatedTarget))
|
|
14
|
+
focused.value = !1;
|
|
15
|
+
};
|
|
16
|
+
el.addEventListener("focusin", onFocusIn, { passive: !0 });
|
|
17
|
+
el.addEventListener("focusout", onFocusOut);
|
|
18
|
+
cleanup = () => {
|
|
19
|
+
el.removeEventListener("focusin", onFocusIn);
|
|
20
|
+
el.removeEventListener("focusout", onFocusOut);
|
|
21
|
+
cleanup = () => {};
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
setup(unref(target));
|
|
25
|
+
try {
|
|
26
|
+
onUnmounted(() => cleanup());
|
|
27
|
+
} catch {}
|
|
28
|
+
return { focused };
|
|
29
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
/**
|
|
3
|
+
* Reactive form primitive with schema validation + submit orchestration.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* const form = useForm({
|
|
8
|
+
* initialValues: { email: '', password: '' },
|
|
9
|
+
* schema: {
|
|
10
|
+
* email: schema.string().email().required(),
|
|
11
|
+
* password: schema.string().min(6).required(),
|
|
12
|
+
* },
|
|
13
|
+
* onSubmit: async (values) => {
|
|
14
|
+
* const r = await authStore.login(values)
|
|
15
|
+
* if (!r.ok) form.setError('form', r.error)
|
|
16
|
+
* },
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function useForm<TValues extends Record<string, unknown>>(opts: UseFormOptions<TValues>): UseFormResult<TValues>;
|
|
21
|
+
/**
|
|
22
|
+
* useForm (stacksjs/stacks#1940 — Phase 1).
|
|
23
|
+
*
|
|
24
|
+
* Per-field state + schema validation + submit orchestration.
|
|
25
|
+
* Builds on `@stacksjs/validation`'s ts-validation surface — pass any
|
|
26
|
+
* field-keyed bag of `schema.string()...` etc. and the composable
|
|
27
|
+
* runs `.validate(value)` to surface the first message.
|
|
28
|
+
*
|
|
29
|
+
* Phase 1 deliberately ships the primitive only; the `<Field>` /
|
|
30
|
+
* `<SubmitButton>` / `<ErrorMessage>` companion components, field
|
|
31
|
+
* arrays, server-error auto-surfacing on 422, and progressive HTML
|
|
32
|
+
* fallback are scoped to Phases 2-5 of the issue.
|
|
33
|
+
*/
|
|
34
|
+
/** Minimal Validator surface this composable depends on. */
|
|
35
|
+
export declare interface FormValidator {
|
|
36
|
+
validate: (value: unknown) => { valid: boolean, errors: Array<{ message: string }> | Record<string, Array<{ message: string }>> }
|
|
37
|
+
}
|
|
38
|
+
export declare interface UseFormOptions<TValues extends Record<string, unknown>> {
|
|
39
|
+
initialValues: TValues
|
|
40
|
+
schema?: Partial<Record<keyof TValues, FormValidator>>
|
|
41
|
+
onSubmit: (values: TValues) => Promise<void> | void
|
|
42
|
+
onError?: (error: Error | Record<string, string>) => void
|
|
43
|
+
validateOn?: ValidationMode
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A ready-to-spread bag of input attributes + handlers for one field
|
|
47
|
+
* (stacksjs/stacks#1940 Phase 2). Encodes the a11y wiring a `<Field>`
|
|
48
|
+
* component would otherwise re-derive by hand: `aria-invalid` flips on a
|
|
49
|
+
* surfaced error, and `aria-describedby` points at the error element's
|
|
50
|
+
* stable id so screen readers announce the message.
|
|
51
|
+
*/
|
|
52
|
+
export declare interface FieldInputProps<T> {
|
|
53
|
+
name: string
|
|
54
|
+
value: T
|
|
55
|
+
onInput: (eventOrValue: unknown) => void
|
|
56
|
+
onBlur: () => void
|
|
57
|
+
'aria-invalid': boolean
|
|
58
|
+
'aria-describedby': string | undefined
|
|
59
|
+
}
|
|
60
|
+
export declare interface FormFieldAccessor<T> {
|
|
61
|
+
value: T
|
|
62
|
+
error: string
|
|
63
|
+
touched: boolean
|
|
64
|
+
dirty: boolean
|
|
65
|
+
errorId: string
|
|
66
|
+
setValue: (next: T) => void
|
|
67
|
+
onBlur: () => void
|
|
68
|
+
validate: () => boolean
|
|
69
|
+
inputProps: () => FieldInputProps<T>
|
|
70
|
+
}
|
|
71
|
+
export declare interface UseFormResult<TValues extends Record<string, unknown>> {
|
|
72
|
+
values: Ref<TValues>
|
|
73
|
+
errors: Ref<Record<string, string>>
|
|
74
|
+
touched: Ref<Record<string, boolean>>
|
|
75
|
+
dirty: Ref<Record<string, boolean>>
|
|
76
|
+
isSubmitting: Ref<boolean>
|
|
77
|
+
isValid: Ref<boolean>
|
|
78
|
+
isDirty: Ref<boolean>
|
|
79
|
+
field: <K extends keyof TValues>(name: K) => FormFieldAccessor<TValues[K]>
|
|
80
|
+
setValue: <K extends keyof TValues>(name: K, value: TValues[K]) => void
|
|
81
|
+
setError: (name: keyof TValues | 'form', message: string) => void
|
|
82
|
+
setErrors: (errorMap: Partial<Record<keyof TValues | 'form', string | string[]>>) => void
|
|
83
|
+
clearErrors: (name?: keyof TValues | 'form') => void
|
|
84
|
+
setTouched: (name: keyof TValues, touched?: boolean) => void
|
|
85
|
+
validate: () => boolean
|
|
86
|
+
handleSubmit: () => Promise<void>
|
|
87
|
+
reset: () => void
|
|
88
|
+
submitButtonProps: () => { type: 'submit', disabled: boolean, 'aria-busy': boolean }
|
|
89
|
+
firstErrorField: () => keyof TValues | null
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Trigger that causes a field to validate.
|
|
93
|
+
* - 'change' — every time the value changes (eager — best for password strength meters)
|
|
94
|
+
* - 'blur' — when the user moves focus away from the field (default — most natural)
|
|
95
|
+
* - 'submit' — only at submit time (lazy — best for short forms with required-only checks)
|
|
96
|
+
*/
|
|
97
|
+
export type ValidationMode = 'change' | 'blur' | 'submit';
|