@stacksjs/composables 0.70.87 → 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 -2
- 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,29 @@
|
|
|
1
|
+
import { onUnmounted, ref } from "@stacksjs/stx";
|
|
2
|
+
export function usePreferredContrast() {
|
|
3
|
+
const contrast = ref("no-preference");
|
|
4
|
+
if (typeof window > "u" || !window.matchMedia)
|
|
5
|
+
return contrast;
|
|
6
|
+
const more = window.matchMedia("(prefers-contrast: more)"), less = window.matchMedia("(prefers-contrast: less)"), custom = window.matchMedia("(prefers-contrast: custom)");
|
|
7
|
+
function update() {
|
|
8
|
+
if (more.matches)
|
|
9
|
+
contrast.value = "more";
|
|
10
|
+
else if (less.matches)
|
|
11
|
+
contrast.value = "less";
|
|
12
|
+
else if (custom.matches)
|
|
13
|
+
contrast.value = "custom";
|
|
14
|
+
else
|
|
15
|
+
contrast.value = "no-preference";
|
|
16
|
+
}
|
|
17
|
+
update();
|
|
18
|
+
more.addEventListener("change", update);
|
|
19
|
+
less.addEventListener("change", update);
|
|
20
|
+
custom.addEventListener("change", update);
|
|
21
|
+
try {
|
|
22
|
+
onUnmounted(() => {
|
|
23
|
+
more.removeEventListener("change", update);
|
|
24
|
+
less.removeEventListener("change", update);
|
|
25
|
+
custom.removeEventListener("change", update);
|
|
26
|
+
});
|
|
27
|
+
} catch {}
|
|
28
|
+
return contrast;
|
|
29
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { onUnmounted, ref } from "@stacksjs/stx";
|
|
2
|
+
export function usePreferredLanguages() {
|
|
3
|
+
const languages = ref(typeof navigator < "u" ? navigator.languages : []);
|
|
4
|
+
if (typeof window > "u")
|
|
5
|
+
return languages;
|
|
6
|
+
const handler = () => {
|
|
7
|
+
languages.value = navigator.languages;
|
|
8
|
+
};
|
|
9
|
+
window.addEventListener("languagechange", handler, { passive: !0 });
|
|
10
|
+
try {
|
|
11
|
+
onUnmounted(() => {
|
|
12
|
+
window.removeEventListener("languagechange", handler);
|
|
13
|
+
});
|
|
14
|
+
} catch {}
|
|
15
|
+
return languages;
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { onUnmounted, ref } from "@stacksjs/stx";
|
|
2
|
+
export function usePreferredReducedMotion() {
|
|
3
|
+
const motion = ref("no-preference");
|
|
4
|
+
if (typeof window > "u" || !window.matchMedia)
|
|
5
|
+
return motion;
|
|
6
|
+
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
7
|
+
function update() {
|
|
8
|
+
motion.value = mq.matches ? "reduce" : "no-preference";
|
|
9
|
+
}
|
|
10
|
+
update();
|
|
11
|
+
mq.addEventListener("change", update);
|
|
12
|
+
try {
|
|
13
|
+
onUnmounted(() => {
|
|
14
|
+
mq.removeEventListener("change", update);
|
|
15
|
+
});
|
|
16
|
+
} catch {}
|
|
17
|
+
return motion;
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
/**
|
|
3
|
+
* Track the previous value of a ref.
|
|
4
|
+
* Returns a ref containing the value before the last change.
|
|
5
|
+
*
|
|
6
|
+
* @param value - The source ref to track
|
|
7
|
+
* @param initialValue - Optional initial value for the previous ref
|
|
8
|
+
*/
|
|
9
|
+
export declare function usePrevious<T>(value: Ref<T>, initialValue?: T): Ref<T | undefined>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
export declare function createQueryClient(options?: CreateQueryClientOptions): QueryClient;
|
|
3
|
+
/**
|
|
4
|
+
* Reactive query with cache + dedup + stale-while-revalidate.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const judges = useQuery({
|
|
9
|
+
* queryKey: ['judges', { practiceArea: filter() }],
|
|
10
|
+
* queryFn: async ({ signal }) => {
|
|
11
|
+
* const res = await fetch('/api/judges', { signal })
|
|
12
|
+
* return res.json() as Promise<Judge[]>
|
|
13
|
+
* },
|
|
14
|
+
* staleTime: 30_000,
|
|
15
|
+
* })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function useQuery<T>(opts: UseQueryOptions<T>): UseQueryResult<T>;
|
|
19
|
+
/**
|
|
20
|
+
* Reactive write-side primitive. Pairs with `useQuery` via
|
|
21
|
+
* `queryClient.invalidate(...)` inside `onSettled` for the canonical
|
|
22
|
+
* optimistic-with-rollback pattern.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useMutation<TData, TVars = void, TCtx = unknown>(opts: UseMutationOptions<TData, TVars, TCtx>): UseMutationResult<TData, TVars>;
|
|
25
|
+
/** Default app-wide client. Tests should pass their own via `client:`. */
|
|
26
|
+
export declare const queryClient: QueryClient;
|
|
27
|
+
declare interface CacheEntry<T = unknown> {
|
|
28
|
+
key: QueryKey
|
|
29
|
+
hash: string
|
|
30
|
+
data: T | undefined
|
|
31
|
+
error: Error | null
|
|
32
|
+
updatedAt: number
|
|
33
|
+
status: 'idle' | 'fetching' | 'success' | 'error'
|
|
34
|
+
inflight: Promise<T> | null
|
|
35
|
+
invalidated: boolean
|
|
36
|
+
subscribers: Set<() => unknown>
|
|
37
|
+
}
|
|
38
|
+
export declare interface CreateQueryClientOptions {
|
|
39
|
+
gcTime?: number
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Central cache. Hold one per app (the default `queryClient` export)
|
|
43
|
+
* or create scoped ones for tests.
|
|
44
|
+
*/
|
|
45
|
+
export declare interface QueryClient {
|
|
46
|
+
get: <T = unknown>(key: QueryKey) => T | undefined
|
|
47
|
+
set: <T = unknown>(key: QueryKey, value: T | ((old: T | undefined) => T)) => void
|
|
48
|
+
invalidate: (matcher: QueryMatcher) => Promise<void>
|
|
49
|
+
clear: () => void
|
|
50
|
+
gc: () => number
|
|
51
|
+
_subscribe: (hash: string, fn: () => unknown) => () => void
|
|
52
|
+
_entry: <T = unknown>(key: QueryKey) => CacheEntry<T>
|
|
53
|
+
_notify: (hash: string) => void
|
|
54
|
+
}
|
|
55
|
+
export declare interface UseQueryOptions<T> {
|
|
56
|
+
queryKey: QueryKey
|
|
57
|
+
queryFn: (ctx: { signal: AbortSignal }) => Promise<T>
|
|
58
|
+
staleTime?: number
|
|
59
|
+
enabled?: boolean
|
|
60
|
+
refetchOnFocus?: boolean
|
|
61
|
+
refetchOnReconnect?: boolean
|
|
62
|
+
window?: EventTarget
|
|
63
|
+
client?: QueryClient
|
|
64
|
+
}
|
|
65
|
+
export declare interface UseQueryResult<T> {
|
|
66
|
+
data: Ref<T | undefined>
|
|
67
|
+
error: Ref<Error | null>
|
|
68
|
+
isLoading: Ref<boolean>
|
|
69
|
+
isFetching: Ref<boolean>
|
|
70
|
+
refetch: () => Promise<void>
|
|
71
|
+
unsubscribe: () => void
|
|
72
|
+
}
|
|
73
|
+
export declare interface UseMutationOptions<TData, TVars, TCtx = unknown> {
|
|
74
|
+
mutationFn: (vars: TVars) => Promise<TData>
|
|
75
|
+
onMutate?: (vars: TVars) => Promise<TCtx> | TCtx
|
|
76
|
+
onSuccess?: (data: TData, vars: TVars, ctx: TCtx | undefined) => void | Promise<void>
|
|
77
|
+
onError?: (error: Error, vars: TVars, ctx: TCtx | undefined) => void | Promise<void>
|
|
78
|
+
onSettled?: (data: TData | undefined, error: Error | null, vars: TVars, ctx: TCtx | undefined) => void | Promise<void>
|
|
79
|
+
}
|
|
80
|
+
export declare interface UseMutationResult<TData, TVars> {
|
|
81
|
+
data: Ref<TData | undefined>
|
|
82
|
+
error: Ref<Error | null>
|
|
83
|
+
isPending: Ref<boolean>
|
|
84
|
+
mutate: (vars: TVars) => void
|
|
85
|
+
mutateAsync: (vars: TVars) => Promise<TData>
|
|
86
|
+
reset: () => void
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* useQuery / useMutation / queryClient (stacksjs/stacks#1939 — Phase A).
|
|
90
|
+
*
|
|
91
|
+
* Cache + dedup + invalidation primitives. Mirrors TanStack Query shape
|
|
92
|
+
* so adopters transfer immediately. Phase A intentionally omits:
|
|
93
|
+
* - `refetchOnFocus` / `refetchOnReconnect` (DOM listener coupling)
|
|
94
|
+
* - automatic GC of unsubscribed cache entries
|
|
95
|
+
* - query key partial-match invalidation via predicate functions
|
|
96
|
+
* Those land in Phase B. Prefix-match invalidation IS supported
|
|
97
|
+
* (`invalidate(['judges'])` matches `['judges', filterObj]` etc).
|
|
98
|
+
*/
|
|
99
|
+
export type QueryKey = readonly unknown[];
|
|
100
|
+
/**
|
|
101
|
+
* Matcher for `invalidate`. Either a `QueryKey` (prefix match, the common
|
|
102
|
+
* case) or a predicate run against every cached key (stacksjs/stacks#1939
|
|
103
|
+
* Phase B) — e.g. invalidate everything tagged a given entity:
|
|
104
|
+
* `invalidate({ predicate: k => k.includes('judges') })`.
|
|
105
|
+
*/
|
|
106
|
+
export type QueryMatcher = QueryKey | { predicate: (key: QueryKey) => boolean }
|
package/dist/useQuery.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { ref } from "@stacksjs/stx";
|
|
2
|
+
function stableStringify(value) {
|
|
3
|
+
if (value === null || typeof value !== "object")
|
|
4
|
+
return JSON.stringify(value);
|
|
5
|
+
if (Array.isArray(value))
|
|
6
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
7
|
+
return `{${Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(",")}}`;
|
|
8
|
+
}
|
|
9
|
+
function hashKey(key) {
|
|
10
|
+
return stableStringify(key);
|
|
11
|
+
}
|
|
12
|
+
export function createQueryClient(options = {}) {
|
|
13
|
+
const entries = new Map, gcTime = options.gcTime ?? 300000, gcTimers = new Map;
|
|
14
|
+
function collectable(e) {
|
|
15
|
+
return e.subscribers.size === 0 && e.inflight === null;
|
|
16
|
+
}
|
|
17
|
+
function removeIfCollectable(hash) {
|
|
18
|
+
const e = entries.get(hash);
|
|
19
|
+
if (e && collectable(e))
|
|
20
|
+
entries.delete(hash);
|
|
21
|
+
gcTimers.delete(hash);
|
|
22
|
+
}
|
|
23
|
+
function scheduleGc(hash) {
|
|
24
|
+
const existing = gcTimers.get(hash);
|
|
25
|
+
if (existing)
|
|
26
|
+
clearTimeout(existing);
|
|
27
|
+
if (!Number.isFinite(gcTime))
|
|
28
|
+
return;
|
|
29
|
+
if (gcTime <= 0) {
|
|
30
|
+
removeIfCollectable(hash);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const t = setTimeout(() => removeIfCollectable(hash), gcTime);
|
|
34
|
+
t.unref?.();
|
|
35
|
+
gcTimers.set(hash, t);
|
|
36
|
+
}
|
|
37
|
+
function cancelGc(hash) {
|
|
38
|
+
const t = gcTimers.get(hash);
|
|
39
|
+
if (t) {
|
|
40
|
+
clearTimeout(t);
|
|
41
|
+
gcTimers.delete(hash);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function entry(key) {
|
|
45
|
+
const hash = hashKey(key);
|
|
46
|
+
let e = entries.get(hash);
|
|
47
|
+
if (!e) {
|
|
48
|
+
e = {
|
|
49
|
+
key,
|
|
50
|
+
hash,
|
|
51
|
+
data: void 0,
|
|
52
|
+
error: null,
|
|
53
|
+
updatedAt: 0,
|
|
54
|
+
status: "idle",
|
|
55
|
+
inflight: null,
|
|
56
|
+
invalidated: !1,
|
|
57
|
+
subscribers: new Set
|
|
58
|
+
};
|
|
59
|
+
entries.set(hash, e);
|
|
60
|
+
}
|
|
61
|
+
return e;
|
|
62
|
+
}
|
|
63
|
+
function notify(hash) {
|
|
64
|
+
const e = entries.get(hash);
|
|
65
|
+
if (!e)
|
|
66
|
+
return;
|
|
67
|
+
for (const fn of e.subscribers)
|
|
68
|
+
fn();
|
|
69
|
+
}
|
|
70
|
+
function prefixMatches(prefix, candidate) {
|
|
71
|
+
if (prefix.length > candidate.length)
|
|
72
|
+
return !1;
|
|
73
|
+
for (let i = 0;i < prefix.length; i++)
|
|
74
|
+
if (stableStringify(prefix[i]) !== stableStringify(candidate[i]))
|
|
75
|
+
return !1;
|
|
76
|
+
return !0;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
get(key) {
|
|
80
|
+
const hash = hashKey(key);
|
|
81
|
+
return entries.get(hash)?.data;
|
|
82
|
+
},
|
|
83
|
+
set(key, value) {
|
|
84
|
+
const e = entry(key), next = typeof value === "function" ? value(e.data) : value;
|
|
85
|
+
e.data = next;
|
|
86
|
+
e.updatedAt = Date.now();
|
|
87
|
+
e.status = "success";
|
|
88
|
+
e.error = null;
|
|
89
|
+
e.invalidated = !1;
|
|
90
|
+
notify(e.hash);
|
|
91
|
+
},
|
|
92
|
+
async invalidate(matcher) {
|
|
93
|
+
const matches = Array.isArray(matcher) ? (key) => prefixMatches(matcher, key) : matcher.predicate, refetches = [];
|
|
94
|
+
for (const e of entries.values()) {
|
|
95
|
+
if (!matches(e.key))
|
|
96
|
+
continue;
|
|
97
|
+
e.updatedAt = 0;
|
|
98
|
+
e.invalidated = !0;
|
|
99
|
+
for (const fn of e.subscribers) {
|
|
100
|
+
const result = fn();
|
|
101
|
+
if (result && typeof result.then === "function")
|
|
102
|
+
refetches.push(result);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
await Promise.all(refetches);
|
|
106
|
+
},
|
|
107
|
+
clear() {
|
|
108
|
+
for (const t of gcTimers.values())
|
|
109
|
+
clearTimeout(t);
|
|
110
|
+
gcTimers.clear();
|
|
111
|
+
entries.clear();
|
|
112
|
+
},
|
|
113
|
+
gc() {
|
|
114
|
+
let removed = 0;
|
|
115
|
+
for (const [hash, e] of entries)
|
|
116
|
+
if (collectable(e)) {
|
|
117
|
+
entries.delete(hash);
|
|
118
|
+
cancelGc(hash);
|
|
119
|
+
removed++;
|
|
120
|
+
}
|
|
121
|
+
return removed;
|
|
122
|
+
},
|
|
123
|
+
_subscribe(hash, fn) {
|
|
124
|
+
const e = entries.get(hash);
|
|
125
|
+
if (!e)
|
|
126
|
+
return () => {};
|
|
127
|
+
cancelGc(hash);
|
|
128
|
+
e.subscribers.add(fn);
|
|
129
|
+
return () => {
|
|
130
|
+
e.subscribers.delete(fn);
|
|
131
|
+
if (e.subscribers.size === 0)
|
|
132
|
+
scheduleGc(hash);
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
_entry: entry,
|
|
136
|
+
_notify: notify
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export const queryClient = createQueryClient();
|
|
140
|
+
export function useQuery(opts) {
|
|
141
|
+
const client = opts.client ?? queryClient, staleTime = opts.staleTime ?? 0, enabled = opts.enabled ?? !0, e = client._entry(opts.queryKey), data = ref(e.data), error = ref(e.error), isLoading = ref(e.data === void 0 && enabled), isFetching = ref(!1);
|
|
142
|
+
function sync() {
|
|
143
|
+
data.value = e.data;
|
|
144
|
+
error.value = e.error;
|
|
145
|
+
isFetching.value = e.status === "fetching";
|
|
146
|
+
if (e.data !== void 0 || e.error !== null)
|
|
147
|
+
isLoading.value = !1;
|
|
148
|
+
}
|
|
149
|
+
async function doFetch(force) {
|
|
150
|
+
if (!force) {
|
|
151
|
+
if (e.data !== void 0 && Date.now() - e.updatedAt < staleTime) {
|
|
152
|
+
sync();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (e.inflight) {
|
|
157
|
+
try {
|
|
158
|
+
await e.inflight;
|
|
159
|
+
} catch {}
|
|
160
|
+
sync();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const controller = new AbortController;
|
|
164
|
+
e.status = "fetching";
|
|
165
|
+
isFetching.value = !0;
|
|
166
|
+
if (e.data === void 0)
|
|
167
|
+
isLoading.value = !0;
|
|
168
|
+
const p = opts.queryFn({ signal: controller.signal }).then((result) => {
|
|
169
|
+
e.data = result;
|
|
170
|
+
e.error = null;
|
|
171
|
+
e.updatedAt = Date.now();
|
|
172
|
+
e.status = "success";
|
|
173
|
+
e.invalidated = !1;
|
|
174
|
+
return result;
|
|
175
|
+
}).catch((err) => {
|
|
176
|
+
e.error = err instanceof Error ? err : Error(String(err));
|
|
177
|
+
e.status = "error";
|
|
178
|
+
e.invalidated = !1;
|
|
179
|
+
throw e.error;
|
|
180
|
+
}).finally(() => {
|
|
181
|
+
e.inflight = null;
|
|
182
|
+
client._notify(e.hash);
|
|
183
|
+
});
|
|
184
|
+
e.inflight = p;
|
|
185
|
+
try {
|
|
186
|
+
await p;
|
|
187
|
+
} catch {}
|
|
188
|
+
sync();
|
|
189
|
+
}
|
|
190
|
+
const unsubscribeCache = client._subscribe(e.hash, () => {
|
|
191
|
+
if (e.invalidated && enabled && e.status !== "fetching")
|
|
192
|
+
return doFetch(!0);
|
|
193
|
+
sync();
|
|
194
|
+
return;
|
|
195
|
+
}), target = opts.window ?? (typeof window < "u" ? window : void 0), winListeners = [];
|
|
196
|
+
if (target && enabled) {
|
|
197
|
+
const onWake = () => {
|
|
198
|
+
if (e.status !== "fetching")
|
|
199
|
+
doFetch(!1);
|
|
200
|
+
};
|
|
201
|
+
if (opts.refetchOnFocus)
|
|
202
|
+
winListeners.push(["focus", onWake]);
|
|
203
|
+
if (opts.refetchOnReconnect)
|
|
204
|
+
winListeners.push(["online", onWake]);
|
|
205
|
+
for (const [evt, fn] of winListeners)
|
|
206
|
+
target.addEventListener(evt, fn);
|
|
207
|
+
}
|
|
208
|
+
function unsubscribe() {
|
|
209
|
+
unsubscribeCache();
|
|
210
|
+
if (target)
|
|
211
|
+
for (const [evt, fn] of winListeners)
|
|
212
|
+
target.removeEventListener(evt, fn);
|
|
213
|
+
}
|
|
214
|
+
if (enabled)
|
|
215
|
+
doFetch(!1);
|
|
216
|
+
else
|
|
217
|
+
sync();
|
|
218
|
+
return {
|
|
219
|
+
data,
|
|
220
|
+
error,
|
|
221
|
+
isLoading,
|
|
222
|
+
isFetching,
|
|
223
|
+
refetch: () => doFetch(!0),
|
|
224
|
+
unsubscribe
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
export function useMutation(opts) {
|
|
228
|
+
const data = ref(void 0), error = ref(null), isPending = ref(!1);
|
|
229
|
+
async function run(vars) {
|
|
230
|
+
isPending.value = !0;
|
|
231
|
+
error.value = null;
|
|
232
|
+
let ctx;
|
|
233
|
+
try {
|
|
234
|
+
if (opts.onMutate)
|
|
235
|
+
ctx = await opts.onMutate(vars);
|
|
236
|
+
const result = await opts.mutationFn(vars);
|
|
237
|
+
data.value = result;
|
|
238
|
+
await opts.onSuccess?.(result, vars, ctx);
|
|
239
|
+
await opts.onSettled?.(result, null, vars, ctx);
|
|
240
|
+
return result;
|
|
241
|
+
} catch (err) {
|
|
242
|
+
const e = err instanceof Error ? err : Error(String(err));
|
|
243
|
+
error.value = e;
|
|
244
|
+
await opts.onError?.(e, vars, ctx);
|
|
245
|
+
await opts.onSettled?.(void 0, e, vars, ctx);
|
|
246
|
+
throw e;
|
|
247
|
+
} finally {
|
|
248
|
+
isPending.value = !1;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
data,
|
|
253
|
+
error,
|
|
254
|
+
isPending,
|
|
255
|
+
mutate(vars) {
|
|
256
|
+
run(vars).catch(() => {});
|
|
257
|
+
},
|
|
258
|
+
mutateAsync: run,
|
|
259
|
+
reset() {
|
|
260
|
+
data.value = void 0;
|
|
261
|
+
error.value = null;
|
|
262
|
+
isPending.value = !1;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
/**
|
|
3
|
+
* Call a function on every requestAnimationFrame.
|
|
4
|
+
* Provides pause/resume controls and auto-cleanup on unmount.
|
|
5
|
+
*
|
|
6
|
+
* @param fn - The callback invoked on each animation frame, receives { delta, timestamp }
|
|
7
|
+
* @param options - Configuration options (immediate defaults to true)
|
|
8
|
+
* @returns Controls to pause, resume, and check active state
|
|
9
|
+
*/
|
|
10
|
+
export declare function useRafFn(fn: (args: UseRafFnCallbackArgs) => void, options?: { immediate?: boolean }): UseRafFnReturn;
|
|
11
|
+
declare interface UseRafFnCallbackArgs {
|
|
12
|
+
delta: number
|
|
13
|
+
timestamp: number
|
|
14
|
+
}
|
|
15
|
+
declare interface UseRafFnReturn {
|
|
16
|
+
pause: () => void
|
|
17
|
+
resume: () => void
|
|
18
|
+
isActive: Ref<boolean>
|
|
19
|
+
}
|
package/dist/useRafFn.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { onUnmounted, ref } from "@stacksjs/stx";
|
|
2
|
+
export function useRafFn(fn, options = {}) {
|
|
3
|
+
const { immediate = !0 } = options, isActive = ref(!1);
|
|
4
|
+
let rafId = null, previousTimestamp = 0;
|
|
5
|
+
function loop(timestamp) {
|
|
6
|
+
if (!isActive.value)
|
|
7
|
+
return;
|
|
8
|
+
const delta = previousTimestamp ? timestamp - previousTimestamp : 0;
|
|
9
|
+
previousTimestamp = timestamp;
|
|
10
|
+
fn({ delta, timestamp });
|
|
11
|
+
rafId = requestAnimationFrame(loop);
|
|
12
|
+
}
|
|
13
|
+
function resume() {
|
|
14
|
+
if (isActive.value)
|
|
15
|
+
return;
|
|
16
|
+
if (typeof requestAnimationFrame > "u")
|
|
17
|
+
return;
|
|
18
|
+
isActive.value = !0;
|
|
19
|
+
previousTimestamp = 0;
|
|
20
|
+
rafId = requestAnimationFrame(loop);
|
|
21
|
+
}
|
|
22
|
+
function pause() {
|
|
23
|
+
if (!isActive.value)
|
|
24
|
+
return;
|
|
25
|
+
isActive.value = !1;
|
|
26
|
+
if (rafId !== null && typeof cancelAnimationFrame < "u") {
|
|
27
|
+
cancelAnimationFrame(rafId);
|
|
28
|
+
rafId = null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (immediate)
|
|
32
|
+
resume();
|
|
33
|
+
try {
|
|
34
|
+
onUnmounted(pause);
|
|
35
|
+
} catch {}
|
|
36
|
+
return { pause, resume, isActive };
|
|
37
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
/**
|
|
3
|
+
* Auto-tracked ref history with undo/redo.
|
|
4
|
+
* Automatically commits a snapshot on every change to the source ref.
|
|
5
|
+
*
|
|
6
|
+
* @param source - The reactive source to track
|
|
7
|
+
* @param options - Capacity limit, deep watching, and clone behavior
|
|
8
|
+
*/
|
|
9
|
+
export declare function useRefHistory<T>(source: Ref<T>, options?: UseRefHistoryOptions): UseRefHistoryReturn<T>;
|
|
10
|
+
export declare interface UseRefHistoryRecord<T> {
|
|
11
|
+
snapshot: T
|
|
12
|
+
timestamp: number
|
|
13
|
+
}
|
|
14
|
+
export declare interface UseRefHistoryOptions {
|
|
15
|
+
capacity?: number
|
|
16
|
+
deep?: boolean
|
|
17
|
+
clone?: boolean
|
|
18
|
+
}
|
|
19
|
+
export declare interface UseRefHistoryReturn<T> {
|
|
20
|
+
history: Ref<UseRefHistoryRecord<T>[]>
|
|
21
|
+
commit: () => void
|
|
22
|
+
undo: () => void
|
|
23
|
+
redo: () => void
|
|
24
|
+
canUndo: Ref<boolean>
|
|
25
|
+
canRedo: Ref<boolean>
|
|
26
|
+
clear: () => void
|
|
27
|
+
last: Ref<UseRefHistoryRecord<T>>
|
|
28
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { computed, ref, watch } from "@stacksjs/stx";
|
|
2
|
+
function cloneValue(val, shouldClone) {
|
|
3
|
+
if (!shouldClone)
|
|
4
|
+
return val;
|
|
5
|
+
if (typeof structuredClone === "function")
|
|
6
|
+
return structuredClone(val);
|
|
7
|
+
return JSON.parse(JSON.stringify(val));
|
|
8
|
+
}
|
|
9
|
+
export function useRefHistory(source, options = {}) {
|
|
10
|
+
const { capacity = 1 / 0, deep = !1, clone = !1 } = options, undoStack = ref([
|
|
11
|
+
{ snapshot: cloneValue(source.value, clone), timestamp: Date.now() }
|
|
12
|
+
]), redoStack = ref([]);
|
|
13
|
+
let isUndoRedoing = !1;
|
|
14
|
+
const canUndo = computed(() => undoStack.value.length > 1), canRedo = computed(() => redoStack.value.length > 0), last = computed(() => {
|
|
15
|
+
return undoStack.value[undoStack.value.length - 1];
|
|
16
|
+
});
|
|
17
|
+
function commit() {
|
|
18
|
+
const record = {
|
|
19
|
+
snapshot: cloneValue(source.value, clone),
|
|
20
|
+
timestamp: Date.now()
|
|
21
|
+
};
|
|
22
|
+
undoStack.value = [...undoStack.value, record];
|
|
23
|
+
if (capacity !== 1 / 0 && undoStack.value.length > capacity)
|
|
24
|
+
undoStack.value = undoStack.value.slice(undoStack.value.length - capacity);
|
|
25
|
+
redoStack.value = [];
|
|
26
|
+
}
|
|
27
|
+
function undo() {
|
|
28
|
+
if (undoStack.value.length <= 1)
|
|
29
|
+
return;
|
|
30
|
+
isUndoRedoing = !0;
|
|
31
|
+
const current = undoStack.value[undoStack.value.length - 1], newUndoStack = undoStack.value.slice(0, -1);
|
|
32
|
+
undoStack.value = newUndoStack;
|
|
33
|
+
if (current)
|
|
34
|
+
redoStack.value = [...redoStack.value, current];
|
|
35
|
+
const previous = newUndoStack[newUndoStack.length - 1];
|
|
36
|
+
if (previous)
|
|
37
|
+
source.value = cloneValue(previous.snapshot, clone);
|
|
38
|
+
isUndoRedoing = !1;
|
|
39
|
+
}
|
|
40
|
+
function redo() {
|
|
41
|
+
if (redoStack.value.length === 0)
|
|
42
|
+
return;
|
|
43
|
+
isUndoRedoing = !0;
|
|
44
|
+
const next = redoStack.value[redoStack.value.length - 1];
|
|
45
|
+
redoStack.value = redoStack.value.slice(0, -1);
|
|
46
|
+
if (next) {
|
|
47
|
+
undoStack.value = [...undoStack.value, next];
|
|
48
|
+
source.value = cloneValue(next.snapshot, clone);
|
|
49
|
+
}
|
|
50
|
+
isUndoRedoing = !1;
|
|
51
|
+
}
|
|
52
|
+
function clear() {
|
|
53
|
+
undoStack.value = [
|
|
54
|
+
{ snapshot: cloneValue(source.value, clone), timestamp: Date.now() }
|
|
55
|
+
];
|
|
56
|
+
redoStack.value = [];
|
|
57
|
+
}
|
|
58
|
+
watch(source, () => {
|
|
59
|
+
if (!isUndoRedoing)
|
|
60
|
+
commit();
|
|
61
|
+
}, { deep });
|
|
62
|
+
return {
|
|
63
|
+
history: undoStack,
|
|
64
|
+
commit,
|
|
65
|
+
undo,
|
|
66
|
+
redo,
|
|
67
|
+
canUndo,
|
|
68
|
+
canRedo,
|
|
69
|
+
clear,
|
|
70
|
+
last
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type MaybeRef } from './_shared';
|
|
2
|
+
import type { Ref } from '@stacksjs/stx';
|
|
3
|
+
/**
|
|
4
|
+
* Reactive ResizeObserver.
|
|
5
|
+
* Observes the target element and calls the callback when the element is resized.
|
|
6
|
+
*
|
|
7
|
+
* @param target - The element to observe (or a Ref to one)
|
|
8
|
+
* @param callback - ResizeObserverCallback
|
|
9
|
+
* @param options - ResizeObserverOptions
|
|
10
|
+
* @returns isSupported ref and stop function
|
|
11
|
+
*/
|
|
12
|
+
export declare function useResizeObserver(target: MaybeRef<HTMLElement | null>, callback: ResizeObserverCallback, options?: ResizeObserverOptions): UseResizeObserverReturn;
|
|
13
|
+
export declare interface UseResizeObserverReturn {
|
|
14
|
+
isSupported: Ref<boolean>
|
|
15
|
+
stop: () => void
|
|
16
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { onUnmounted, ref } from "@stacksjs/stx";
|
|
2
|
+
import { unref, noop } from "./_shared";
|
|
3
|
+
export function useResizeObserver(target, callback, options) {
|
|
4
|
+
const isSupported = ref(typeof window < "u" && "ResizeObserver" in window);
|
|
5
|
+
let cleanup = noop;
|
|
6
|
+
(() => {
|
|
7
|
+
cleanup();
|
|
8
|
+
if (!isSupported.value)
|
|
9
|
+
return;
|
|
10
|
+
const el = unref(target);
|
|
11
|
+
if (!el)
|
|
12
|
+
return;
|
|
13
|
+
const observer = new ResizeObserver(callback);
|
|
14
|
+
observer.observe(el, options);
|
|
15
|
+
cleanup = () => {
|
|
16
|
+
observer.disconnect();
|
|
17
|
+
cleanup = noop;
|
|
18
|
+
};
|
|
19
|
+
})();
|
|
20
|
+
const stop = () => {
|
|
21
|
+
cleanup();
|
|
22
|
+
};
|
|
23
|
+
try {
|
|
24
|
+
onUnmounted(stop);
|
|
25
|
+
} catch {}
|
|
26
|
+
return { isSupported, stop };
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
/**
|
|
3
|
+
* Reactive Screen Orientation API.
|
|
4
|
+
*/
|
|
5
|
+
export declare function useScreenOrientation(): UseScreenOrientationReturn;
|
|
6
|
+
export declare interface UseScreenOrientationReturn {
|
|
7
|
+
isSupported: Ref<boolean>
|
|
8
|
+
orientation: Ref<string | undefined>
|
|
9
|
+
angle: Ref<number>
|
|
10
|
+
lockOrientation: (type: ScreenOrientationLockType) => Promise<void>
|
|
11
|
+
unlockOrientation: () => void
|
|
12
|
+
}
|
|
13
|
+
declare type ScreenOrientationLockType = 'any' | 'natural' | 'landscape' | 'portrait' | 'portrait-primary' | 'portrait-secondary' | 'landscape-primary' | 'landscape-secondary';
|