@reause/integrations 0.1.2
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/LICENSE +21 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.iife.js +1621 -0
- package/dist/index.iife.min.js +1 -0
- package/dist/index.js +13 -0
- package/dist/useAsyncValidator.d.ts +83 -0
- package/dist/useAsyncValidator.iife.js +192 -0
- package/dist/useAsyncValidator.iife.min.js +1 -0
- package/dist/useAsyncValidator.js +168 -0
- package/dist/useAxios.d.ts +125 -0
- package/dist/useAxios.iife.js +288 -0
- package/dist/useAxios.iife.min.js +1 -0
- package/dist/useAxios.js +265 -0
- package/dist/useChangeCase.d.ts +57 -0
- package/dist/useChangeCase.iife.js +91 -0
- package/dist/useChangeCase.iife.min.js +1 -0
- package/dist/useChangeCase.js +68 -0
- package/dist/useCookies.d.ts +117 -0
- package/dist/useCookies.iife.js +142 -0
- package/dist/useCookies.iife.min.js +1 -0
- package/dist/useCookies.js +117 -0
- package/dist/useDrauu.d.ts +152 -0
- package/dist/useDrauu.iife.js +221 -0
- package/dist/useDrauu.iife.min.js +1 -0
- package/dist/useDrauu.js +221 -0
- package/dist/useFocusTrap.d.ts +116 -0
- package/dist/useFocusTrap.iife.js +125 -0
- package/dist/useFocusTrap.iife.min.js +1 -0
- package/dist/useFocusTrap.js +125 -0
- package/dist/useFuse.d.ts +86 -0
- package/dist/useFuse.iife.js +95 -0
- package/dist/useFuse.iife.min.js +1 -0
- package/dist/useFuse.js +72 -0
- package/dist/useIDBKeyval.d.ts +139 -0
- package/dist/useIDBKeyval.iife.js +175 -0
- package/dist/useIDBKeyval.iife.min.js +1 -0
- package/dist/useIDBKeyval.js +174 -0
- package/dist/useJwt.d.ts +52 -0
- package/dist/useJwt.iife.js +54 -0
- package/dist/useJwt.iife.min.js +1 -0
- package/dist/useJwt.js +53 -0
- package/dist/useNProgress.d.ts +115 -0
- package/dist/useNProgress.iife.js +148 -0
- package/dist/useNProgress.iife.min.js +1 -0
- package/dist/useNProgress.js +125 -0
- package/dist/useQRCode.d.ts +38 -0
- package/dist/useQRCode.iife.js +78 -0
- package/dist/useQRCode.iife.min.js +1 -0
- package/dist/useQRCode.js +55 -0
- package/dist/useSortable.d.ts +143 -0
- package/dist/useSortable.iife.js +199 -0
- package/dist/useSortable.iife.min.js +1 -0
- package/dist/useSortable.js +173 -0
- package/package.json +92 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { RefOrValue } from "@reause/shared";
|
|
2
|
+
import * as FocusTrap from "focus-trap";
|
|
3
|
+
//#region useFocusTrap/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Activate options accepted by `useFocusTrap().activate()` — mirrors
|
|
6
|
+
* focus-trap's non-exported `ActivateOptions`.
|
|
7
|
+
*/
|
|
8
|
+
type ActivateOptions = NonNullable<Parameters<FocusTrap.FocusTrap['activate']>[0]>;
|
|
9
|
+
/**
|
|
10
|
+
* Deactivate options accepted by `useFocusTrap().deactivate()` — mirrors
|
|
11
|
+
* focus-trap's non-exported `DeactivateOptions`.
|
|
12
|
+
*/
|
|
13
|
+
type DeactivateOptions = NonNullable<Parameters<FocusTrap.FocusTrap['deactivate']>[0]>;
|
|
14
|
+
export interface UseFocusTrapOptions extends FocusTrap.Options {
|
|
15
|
+
/**
|
|
16
|
+
* Immediately activate the trap
|
|
17
|
+
*/
|
|
18
|
+
immediate?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Called when the trap is activated. Focus-trap's own `Options.onActivate` is
|
|
21
|
+
* typed (and, in the pinned version, invoked) without arguments; this port
|
|
22
|
+
* re-declares it with the optional activation params so they are forwarded
|
|
23
|
+
* exactly like upstream (`options.onActivate(params)`).
|
|
24
|
+
*/
|
|
25
|
+
onActivate?: (params?: ActivateOptions) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Called when the trap is deactivated, receiving the deactivation params.
|
|
28
|
+
* Focus-trap's own `Options.onDeactivate` is typed (and, in the pinned
|
|
29
|
+
* version, invoked) without arguments; this port re-declares it with the
|
|
30
|
+
* optional deactivation params so they are forwarded exactly like upstream
|
|
31
|
+
* (`options.onDeactivate(params)`).
|
|
32
|
+
*/
|
|
33
|
+
onDeactivate?: (params?: DeactivateOptions) => void;
|
|
34
|
+
}
|
|
35
|
+
export interface UseFocusTrapReturn {
|
|
36
|
+
/**
|
|
37
|
+
* Indicates if the focus trap is currently active
|
|
38
|
+
*/
|
|
39
|
+
hasFocus: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Indicates if the focus trap is currently paused
|
|
42
|
+
*/
|
|
43
|
+
isPaused: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Activate the focus trap
|
|
46
|
+
*
|
|
47
|
+
* @see https://github.com/focus-trap/focus-trap#trapactivateactivateoptions
|
|
48
|
+
* @param opts Activate focus trap options
|
|
49
|
+
*/
|
|
50
|
+
activate: (opts?: ActivateOptions) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Deactivate the focus trap
|
|
53
|
+
*
|
|
54
|
+
* @see https://github.com/focus-trap/focus-trap#trapdeactivatedeactivateoptions
|
|
55
|
+
* @param opts Deactivate focus trap options
|
|
56
|
+
*/
|
|
57
|
+
deactivate: (opts?: DeactivateOptions) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Pause the focus trap
|
|
60
|
+
*
|
|
61
|
+
* @see https://github.com/focus-trap/focus-trap#trappause
|
|
62
|
+
*/
|
|
63
|
+
pause: () => void;
|
|
64
|
+
/**
|
|
65
|
+
* Unpauses the focus trap
|
|
66
|
+
*
|
|
67
|
+
* @see https://github.com/focus-trap/focus-trap#trapunpause
|
|
68
|
+
*/
|
|
69
|
+
unpause: () => void;
|
|
70
|
+
}
|
|
71
|
+
/** Accepted DOM target kinds — mirrors upstream's `MaybeElement`. */
|
|
72
|
+
type MaybeElement = HTMLElement | SVGElement | null | undefined;
|
|
73
|
+
/** A plain element or a React ref-like object (`{ current }`) — upstream `MaybeElementRef`. */
|
|
74
|
+
type MaybeElementRef = MaybeElement | {
|
|
75
|
+
readonly current: MaybeElement;
|
|
76
|
+
};
|
|
77
|
+
/** One item of the focus-trap target list (upstream `MaybeComputedElementRef`, without its getter branch). */
|
|
78
|
+
type FocusTrapTarget = RefOrValue<string> | MaybeElementRef;
|
|
79
|
+
/**
|
|
80
|
+
* React port of VueUse's `useFocusTrap` — trap focus within one or more
|
|
81
|
+
* elements.
|
|
82
|
+
*
|
|
83
|
+
* Map from @vueuse/integrations `useFocusTrap`
|
|
84
|
+
* (`source/vueuse/packages/integrations/useFocusTrap/`), a reactive wrapper
|
|
85
|
+
* around the [`focus-trap`](https://github.com/focus-trap/focus-trap) library
|
|
86
|
+
* that keeps focus trapped inside the target element(s) while the trap is
|
|
87
|
+
* active.
|
|
88
|
+
*
|
|
89
|
+
* Adjustment for React: upstream creates the trap inside a `watch` over the
|
|
90
|
+
* resolved targets and exposes `ShallowRef`s for `hasFocus` / `isPaused`. The
|
|
91
|
+
* React port creates the `createFocusTrap` instance in an effect keyed on the
|
|
92
|
+
* resolved targets (mirroring the `watch`), keeps it for the lifetime of the
|
|
93
|
+
* component — target changes go through `updateContainerElements` — and
|
|
94
|
+
* deactivates it on unmount (`tryOnScopeDispose`). `hasFocus` / `isPaused`
|
|
95
|
+
* are plain booleans driven by focus-trap's `onActivate` / `onDeactivate`
|
|
96
|
+
* events plus the pause / unpause calls, and `activate` / `deactivate` /
|
|
97
|
+
* `pause` / `unpause` are stable callbacks delegating to the current trap
|
|
98
|
+
* instance. The `immediate` option activates the trap as soon as the target
|
|
99
|
+
* elements are available.
|
|
100
|
+
*
|
|
101
|
+
* SSR-safe: no `window` or DOM access at module scope — the trap is created
|
|
102
|
+
* lazily inside the effect.
|
|
103
|
+
*
|
|
104
|
+
* @param target - element, React ref object (`{ current }`), selector string,
|
|
105
|
+
* or an array of them
|
|
106
|
+
* @param options - focus-trap options (see
|
|
107
|
+
* https://github.com/focus-trap/focus-trap#createoptions) plus the
|
|
108
|
+
* `immediate` shortcut
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* const target = useRef<HTMLDivElement>(null)
|
|
112
|
+
* const { hasFocus, isPaused, activate, deactivate, pause, unpause } = useFocusTrap(target)
|
|
113
|
+
* activate() // traps focus inside target
|
|
114
|
+
*/
|
|
115
|
+
export declare function useFocusTrap(target: RefOrValue<FocusTrapTarget | FocusTrapTarget[]>, options?: UseFocusTrapOptions): UseFocusTrapReturn;
|
|
116
|
+
//#endregion
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
(function(exports, _reause_shared, focus_trap, react) {
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
//#region useFocusTrap/index.tsx
|
|
4
|
+
/**
|
|
5
|
+
* Resolve one target item to a focus-trap container: a selector string, a DOM
|
|
6
|
+
* element, or `null` when it cannot be resolved. Upstream resolves elements
|
|
7
|
+
* with `unrefElement` (`@vueuse/core`); the React port composes the same
|
|
8
|
+
* unwrapping from `toValue` / `isRefLike` (`@reause/shared`) — one pass
|
|
9
|
+
* unwraps a ref-like object, a second one covers a ref-like object holding
|
|
10
|
+
* another ref-like (`{ current: { current: element } }`).
|
|
11
|
+
*/
|
|
12
|
+
function resolveElement(value) {
|
|
13
|
+
let el = (0, _reause_shared.toValue)(value);
|
|
14
|
+
if (typeof el !== "string" && (0, _reause_shared.isRefLike)(el)) el = (0, _reause_shared.toValue)(el);
|
|
15
|
+
if (typeof el === "string") return el;
|
|
16
|
+
if (typeof el === "object" && el !== null && (el instanceof HTMLElement || el instanceof SVGElement)) return el;
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* React port of VueUse's `useFocusTrap` — trap focus within one or more
|
|
21
|
+
* elements.
|
|
22
|
+
*
|
|
23
|
+
* Map from @vueuse/integrations `useFocusTrap`
|
|
24
|
+
* (`source/vueuse/packages/integrations/useFocusTrap/`), a reactive wrapper
|
|
25
|
+
* around the [`focus-trap`](https://github.com/focus-trap/focus-trap) library
|
|
26
|
+
* that keeps focus trapped inside the target element(s) while the trap is
|
|
27
|
+
* active.
|
|
28
|
+
*
|
|
29
|
+
* Adjustment for React: upstream creates the trap inside a `watch` over the
|
|
30
|
+
* resolved targets and exposes `ShallowRef`s for `hasFocus` / `isPaused`. The
|
|
31
|
+
* React port creates the `createFocusTrap` instance in an effect keyed on the
|
|
32
|
+
* resolved targets (mirroring the `watch`), keeps it for the lifetime of the
|
|
33
|
+
* component — target changes go through `updateContainerElements` — and
|
|
34
|
+
* deactivates it on unmount (`tryOnScopeDispose`). `hasFocus` / `isPaused`
|
|
35
|
+
* are plain booleans driven by focus-trap's `onActivate` / `onDeactivate`
|
|
36
|
+
* events plus the pause / unpause calls, and `activate` / `deactivate` /
|
|
37
|
+
* `pause` / `unpause` are stable callbacks delegating to the current trap
|
|
38
|
+
* instance. The `immediate` option activates the trap as soon as the target
|
|
39
|
+
* elements are available.
|
|
40
|
+
*
|
|
41
|
+
* SSR-safe: no `window` or DOM access at module scope — the trap is created
|
|
42
|
+
* lazily inside the effect.
|
|
43
|
+
*
|
|
44
|
+
* @param target - element, React ref object (`{ current }`), selector string,
|
|
45
|
+
* or an array of them
|
|
46
|
+
* @param options - focus-trap options (see
|
|
47
|
+
* https://github.com/focus-trap/focus-trap#createoptions) plus the
|
|
48
|
+
* `immediate` shortcut
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const target = useRef<HTMLDivElement>(null)
|
|
52
|
+
* const { hasFocus, isPaused, activate, deactivate, pause, unpause } = useFocusTrap(target)
|
|
53
|
+
* activate() // traps focus inside target
|
|
54
|
+
*/
|
|
55
|
+
function useFocusTrap(target, options = {}) {
|
|
56
|
+
const [hasFocus, setHasFocus] = (0, react.useState)(false);
|
|
57
|
+
const [isPaused, setIsPaused] = (0, react.useState)(false);
|
|
58
|
+
const trapRef = (0, react.useRef)(null);
|
|
59
|
+
const targetRef = (0, react.useRef)(target);
|
|
60
|
+
targetRef.current = target;
|
|
61
|
+
const optionsRef = (0, react.useRef)(options);
|
|
62
|
+
optionsRef.current = options;
|
|
63
|
+
const resolvedTargetsRef = (0, react.useRef)(null);
|
|
64
|
+
(0, react.useEffect)(() => {
|
|
65
|
+
const targets = (0, _reause_shared.toArray)((0, _reause_shared.toValue)(targetRef.current)).map(resolveElement).filter((el) => el != null);
|
|
66
|
+
const previous = resolvedTargetsRef.current;
|
|
67
|
+
resolvedTargetsRef.current = targets;
|
|
68
|
+
if (previous && targets.length === previous.length && targets.every((el, index) => el === previous[index])) return;
|
|
69
|
+
if (!targets.length) return;
|
|
70
|
+
const trap = trapRef.current;
|
|
71
|
+
if (!trap) {
|
|
72
|
+
const { immediate, ...focusTrapOptions } = optionsRef.current;
|
|
73
|
+
trapRef.current = (0, focus_trap.createFocusTrap)(targets, {
|
|
74
|
+
...focusTrapOptions,
|
|
75
|
+
onActivate(params) {
|
|
76
|
+
var _optionsRef$current$o, _optionsRef$current;
|
|
77
|
+
setHasFocus(true);
|
|
78
|
+
(_optionsRef$current$o = (_optionsRef$current = optionsRef.current).onActivate) === null || _optionsRef$current$o === void 0 || _optionsRef$current$o.call(_optionsRef$current, params);
|
|
79
|
+
},
|
|
80
|
+
onDeactivate(params) {
|
|
81
|
+
var _optionsRef$current$o2, _optionsRef$current2;
|
|
82
|
+
setHasFocus(false);
|
|
83
|
+
(_optionsRef$current$o2 = (_optionsRef$current2 = optionsRef.current).onDeactivate) === null || _optionsRef$current$o2 === void 0 || _optionsRef$current$o2.call(_optionsRef$current2, params);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
if (immediate) trapRef.current.activate();
|
|
87
|
+
} else {
|
|
88
|
+
const isActive = trap.active;
|
|
89
|
+
trap.updateContainerElements(targets);
|
|
90
|
+
if (!isActive && optionsRef.current.immediate) trap.activate();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
(0, react.useEffect)(() => () => {
|
|
94
|
+
var _trapRef$current;
|
|
95
|
+
(_trapRef$current = trapRef.current) === null || _trapRef$current === void 0 || _trapRef$current.deactivate();
|
|
96
|
+
trapRef.current = null;
|
|
97
|
+
}, []);
|
|
98
|
+
return {
|
|
99
|
+
hasFocus,
|
|
100
|
+
isPaused,
|
|
101
|
+
activate: (0, react.useCallback)((opts) => {
|
|
102
|
+
var _trapRef$current2;
|
|
103
|
+
(_trapRef$current2 = trapRef.current) === null || _trapRef$current2 === void 0 || _trapRef$current2.activate(opts);
|
|
104
|
+
}, []),
|
|
105
|
+
deactivate: (0, react.useCallback)((opts) => {
|
|
106
|
+
var _trapRef$current3;
|
|
107
|
+
(_trapRef$current3 = trapRef.current) === null || _trapRef$current3 === void 0 || _trapRef$current3.deactivate(opts);
|
|
108
|
+
}, []),
|
|
109
|
+
pause: (0, react.useCallback)(() => {
|
|
110
|
+
if (trapRef.current) {
|
|
111
|
+
trapRef.current.pause();
|
|
112
|
+
setIsPaused(true);
|
|
113
|
+
}
|
|
114
|
+
}, []),
|
|
115
|
+
unpause: (0, react.useCallback)(() => {
|
|
116
|
+
if (trapRef.current) {
|
|
117
|
+
trapRef.current.unpause();
|
|
118
|
+
setIsPaused(false);
|
|
119
|
+
}
|
|
120
|
+
}, [])
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
exports.useFocusTrap = useFocusTrap;
|
|
125
|
+
})(this.reause = this.reause || {}, reause, focusTrap, React);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t,n,r){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function i(e){let n=(0,t.toValue)(e);return typeof n!=`string`&&(0,t.isRefLike)(n)&&(n=(0,t.toValue)(n)),typeof n==`string`||typeof n==`object`&&n&&(n instanceof HTMLElement||n instanceof SVGElement)?n:null}function a(e,a={}){let[o,s]=(0,r.useState)(!1),[c,l]=(0,r.useState)(!1),u=(0,r.useRef)(null),d=(0,r.useRef)(e);d.current=e;let f=(0,r.useRef)(a);f.current=a;let p=(0,r.useRef)(null);return(0,r.useEffect)(()=>{let e=(0,t.toArray)((0,t.toValue)(d.current)).map(i).filter(e=>e!=null),r=p.current;if(p.current=e,r&&e.length===r.length&&e.every((e,t)=>e===r[t])||!e.length)return;let a=u.current;if(a){let t=a.active;a.updateContainerElements(e),!t&&f.current.immediate&&a.activate()}else{let{immediate:t,...r}=f.current;u.current=(0,n.createFocusTrap)(e,{...r,onActivate(e){var t,n;s(!0),(t=(n=f.current).onActivate)==null||t.call(n,e)},onDeactivate(e){var t,n;s(!1),(t=(n=f.current).onDeactivate)==null||t.call(n,e)}}),t&&u.current.activate()}}),(0,r.useEffect)(()=>()=>{var e;(e=u.current)==null||e.deactivate(),u.current=null},[]),{hasFocus:o,isPaused:c,activate:(0,r.useCallback)(e=>{var t;(t=u.current)==null||t.activate(e)},[]),deactivate:(0,r.useCallback)(e=>{var t;(t=u.current)==null||t.deactivate(e)},[]),pause:(0,r.useCallback)(()=>{u.current&&(u.current.pause(),l(!0))},[]),unpause:(0,r.useCallback)(()=>{u.current&&(u.current.unpause(),l(!1))},[])}}e.useFocusTrap=a})(this.reause=this.reause||{},reause,focusTrap,React);
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { isRefLike, toArray, toValue } from "@reause/shared";
|
|
3
|
+
import { createFocusTrap } from "focus-trap";
|
|
4
|
+
//#region useFocusTrap/index.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Resolve one target item to a focus-trap container: a selector string, a DOM
|
|
7
|
+
* element, or `null` when it cannot be resolved. Upstream resolves elements
|
|
8
|
+
* with `unrefElement` (`@vueuse/core`); the React port composes the same
|
|
9
|
+
* unwrapping from `toValue` / `isRefLike` (`@reause/shared`) — one pass
|
|
10
|
+
* unwraps a ref-like object, a second one covers a ref-like object holding
|
|
11
|
+
* another ref-like (`{ current: { current: element } }`).
|
|
12
|
+
*/
|
|
13
|
+
function resolveElement(value) {
|
|
14
|
+
let el = toValue(value);
|
|
15
|
+
if (typeof el !== "string" && isRefLike(el)) el = toValue(el);
|
|
16
|
+
if (typeof el === "string") return el;
|
|
17
|
+
if (typeof el === "object" && el !== null && (el instanceof HTMLElement || el instanceof SVGElement)) return el;
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* React port of VueUse's `useFocusTrap` — trap focus within one or more
|
|
22
|
+
* elements.
|
|
23
|
+
*
|
|
24
|
+
* Map from @vueuse/integrations `useFocusTrap`
|
|
25
|
+
* (`source/vueuse/packages/integrations/useFocusTrap/`), a reactive wrapper
|
|
26
|
+
* around the [`focus-trap`](https://github.com/focus-trap/focus-trap) library
|
|
27
|
+
* that keeps focus trapped inside the target element(s) while the trap is
|
|
28
|
+
* active.
|
|
29
|
+
*
|
|
30
|
+
* Adjustment for React: upstream creates the trap inside a `watch` over the
|
|
31
|
+
* resolved targets and exposes `ShallowRef`s for `hasFocus` / `isPaused`. The
|
|
32
|
+
* React port creates the `createFocusTrap` instance in an effect keyed on the
|
|
33
|
+
* resolved targets (mirroring the `watch`), keeps it for the lifetime of the
|
|
34
|
+
* component — target changes go through `updateContainerElements` — and
|
|
35
|
+
* deactivates it on unmount (`tryOnScopeDispose`). `hasFocus` / `isPaused`
|
|
36
|
+
* are plain booleans driven by focus-trap's `onActivate` / `onDeactivate`
|
|
37
|
+
* events plus the pause / unpause calls, and `activate` / `deactivate` /
|
|
38
|
+
* `pause` / `unpause` are stable callbacks delegating to the current trap
|
|
39
|
+
* instance. The `immediate` option activates the trap as soon as the target
|
|
40
|
+
* elements are available.
|
|
41
|
+
*
|
|
42
|
+
* SSR-safe: no `window` or DOM access at module scope — the trap is created
|
|
43
|
+
* lazily inside the effect.
|
|
44
|
+
*
|
|
45
|
+
* @param target - element, React ref object (`{ current }`), selector string,
|
|
46
|
+
* or an array of them
|
|
47
|
+
* @param options - focus-trap options (see
|
|
48
|
+
* https://github.com/focus-trap/focus-trap#createoptions) plus the
|
|
49
|
+
* `immediate` shortcut
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* const target = useRef<HTMLDivElement>(null)
|
|
53
|
+
* const { hasFocus, isPaused, activate, deactivate, pause, unpause } = useFocusTrap(target)
|
|
54
|
+
* activate() // traps focus inside target
|
|
55
|
+
*/
|
|
56
|
+
function useFocusTrap(target, options = {}) {
|
|
57
|
+
const [hasFocus, setHasFocus] = useState(false);
|
|
58
|
+
const [isPaused, setIsPaused] = useState(false);
|
|
59
|
+
const trapRef = useRef(null);
|
|
60
|
+
const targetRef = useRef(target);
|
|
61
|
+
targetRef.current = target;
|
|
62
|
+
const optionsRef = useRef(options);
|
|
63
|
+
optionsRef.current = options;
|
|
64
|
+
const resolvedTargetsRef = useRef(null);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const targets = toArray(toValue(targetRef.current)).map(resolveElement).filter((el) => el != null);
|
|
67
|
+
const previous = resolvedTargetsRef.current;
|
|
68
|
+
resolvedTargetsRef.current = targets;
|
|
69
|
+
if (previous && targets.length === previous.length && targets.every((el, index) => el === previous[index])) return;
|
|
70
|
+
if (!targets.length) return;
|
|
71
|
+
const trap = trapRef.current;
|
|
72
|
+
if (!trap) {
|
|
73
|
+
const { immediate, ...focusTrapOptions } = optionsRef.current;
|
|
74
|
+
trapRef.current = createFocusTrap(targets, {
|
|
75
|
+
...focusTrapOptions,
|
|
76
|
+
onActivate(params) {
|
|
77
|
+
var _optionsRef$current$o, _optionsRef$current;
|
|
78
|
+
setHasFocus(true);
|
|
79
|
+
(_optionsRef$current$o = (_optionsRef$current = optionsRef.current).onActivate) === null || _optionsRef$current$o === void 0 || _optionsRef$current$o.call(_optionsRef$current, params);
|
|
80
|
+
},
|
|
81
|
+
onDeactivate(params) {
|
|
82
|
+
var _optionsRef$current$o2, _optionsRef$current2;
|
|
83
|
+
setHasFocus(false);
|
|
84
|
+
(_optionsRef$current$o2 = (_optionsRef$current2 = optionsRef.current).onDeactivate) === null || _optionsRef$current$o2 === void 0 || _optionsRef$current$o2.call(_optionsRef$current2, params);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
if (immediate) trapRef.current.activate();
|
|
88
|
+
} else {
|
|
89
|
+
const isActive = trap.active;
|
|
90
|
+
trap.updateContainerElements(targets);
|
|
91
|
+
if (!isActive && optionsRef.current.immediate) trap.activate();
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
useEffect(() => () => {
|
|
95
|
+
var _trapRef$current;
|
|
96
|
+
(_trapRef$current = trapRef.current) === null || _trapRef$current === void 0 || _trapRef$current.deactivate();
|
|
97
|
+
trapRef.current = null;
|
|
98
|
+
}, []);
|
|
99
|
+
return {
|
|
100
|
+
hasFocus,
|
|
101
|
+
isPaused,
|
|
102
|
+
activate: useCallback((opts) => {
|
|
103
|
+
var _trapRef$current2;
|
|
104
|
+
(_trapRef$current2 = trapRef.current) === null || _trapRef$current2 === void 0 || _trapRef$current2.activate(opts);
|
|
105
|
+
}, []),
|
|
106
|
+
deactivate: useCallback((opts) => {
|
|
107
|
+
var _trapRef$current3;
|
|
108
|
+
(_trapRef$current3 = trapRef.current) === null || _trapRef$current3 === void 0 || _trapRef$current3.deactivate(opts);
|
|
109
|
+
}, []),
|
|
110
|
+
pause: useCallback(() => {
|
|
111
|
+
if (trapRef.current) {
|
|
112
|
+
trapRef.current.pause();
|
|
113
|
+
setIsPaused(true);
|
|
114
|
+
}
|
|
115
|
+
}, []),
|
|
116
|
+
unpause: useCallback(() => {
|
|
117
|
+
if (trapRef.current) {
|
|
118
|
+
trapRef.current.unpause();
|
|
119
|
+
setIsPaused(false);
|
|
120
|
+
}
|
|
121
|
+
}, [])
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
export { useFocusTrap };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { RefOrValue } from "@reause/shared";
|
|
2
|
+
import Fuse, { FuseResult, IFuseOptions } from "fuse.js";
|
|
3
|
+
//#region useFuse/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Options passed straight through to the underlying `Fuse` instance — alias of
|
|
6
|
+
* fuse.js' `IFuseOptions<T>`.
|
|
7
|
+
*/
|
|
8
|
+
export type FuseOptions<T> = IFuseOptions<T>;
|
|
9
|
+
export interface UseFuseOptions<T> {
|
|
10
|
+
/**
|
|
11
|
+
* Options for the underlying `Fuse` instance.
|
|
12
|
+
*
|
|
13
|
+
* Memoize this object (and the `keys` array inside it) between renders:
|
|
14
|
+
* the `Fuse` index is rebuilt whenever this reference changes. A fresh
|
|
15
|
+
* object literal on every render is still CORRECT, only slower.
|
|
16
|
+
*/
|
|
17
|
+
fuseOptions?: FuseOptions<T>;
|
|
18
|
+
/**
|
|
19
|
+
* Maximum number of results returned by a search. Ignored when
|
|
20
|
+
* `matchAllWhenSearchEmpty` kicks in for an empty search.
|
|
21
|
+
*/
|
|
22
|
+
resultLimit?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Return every item (in its original order) while the search is empty,
|
|
25
|
+
* instead of an empty result list.
|
|
26
|
+
*/
|
|
27
|
+
matchAllWhenSearchEmpty?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* React return type: a plain object, not a tuple — `fuse` and `results` are
|
|
31
|
+
* named, heterogeneous values (`fuse` is the live `Fuse` instance, `results`
|
|
32
|
+
* is a plain array), matching the object-return precedent of
|
|
33
|
+
* `packages/core/src/useBattery.ts` and `packages/core/src/useClipboard.ts`.
|
|
34
|
+
*/
|
|
35
|
+
export interface UseFuseReturn<DataItem> {
|
|
36
|
+
/** The live `Fuse` instance — call `fuse.setCollection()` / `fuse.search()` on it directly. */
|
|
37
|
+
fuse: Fuse<DataItem>;
|
|
38
|
+
/** Fuzzy search results, recomputed on every render. */
|
|
39
|
+
results: FuseResult<DataItem>[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* React port of VueUse's `useFuse` — easily implement fuzzy search with
|
|
43
|
+
* [Fuse.js](https://github.com/krisk/fuse).
|
|
44
|
+
*
|
|
45
|
+
* Map from @vueuse/integrations `useFuse`
|
|
46
|
+
* (`source/vueuse/packages/integrations/useFuse/`), a reactive wrapper around
|
|
47
|
+
* a `Fuse` instance. `search` and `data` are the hook's **read-only value
|
|
48
|
+
* sources** and take plain values (`string` and `readonly DataItem[]`; upstream:
|
|
49
|
+
* `MaybeRefOrGetter`). `options` stays `RefOrValue` (a config object, upstream
|
|
50
|
+
* `MaybeRefOrGetter`).
|
|
51
|
+
*
|
|
52
|
+
* Adjustment for React:
|
|
53
|
+
* - upstream returns `{ fuse: Ref<Fuse>, results: ComputedRef<FuseResult[]> }`;
|
|
54
|
+
* here both are plain values read during render — `fuse` is the `Fuse`
|
|
55
|
+
* instance itself (no `.value`), `results` is a plain array;
|
|
56
|
+
* - upstream rebuilds the index in `watch(() => toValue(options)?.fuseOptions,
|
|
57
|
+
* …, { deep: true })` and refreshes the collection in `watch(() => toValue(data), …)`.
|
|
58
|
+
* React has no deep watcher, and serializing `fuseOptions` to compare them by
|
|
59
|
+
* value would break function-valued options (`sortFn`, `getFn`, `keys[].getFn`),
|
|
60
|
+
* so the `Fuse` instance is memoized on the identity of the `data`
|
|
61
|
+
* array and of `fuseOptions` instead: pass a NEW array reference when the data
|
|
62
|
+
* changes, and a memoized `fuseOptions` object for best performance. Mutating
|
|
63
|
+
* the data array in place is not detected (upstream's deep watch was);
|
|
64
|
+
* - `results` is memoized on the search string and the `data` identity, so a
|
|
65
|
+
* changed `search`/`data` prop recomputes on the next render;
|
|
66
|
+
* - `options` is NOT widened: it is a config object (upstream
|
|
67
|
+
* `MaybeRefOrGetter`, a maintainer decision), so a plain options object, a
|
|
68
|
+
* ref-like `{ current }` object or a getter are the accepted forms.
|
|
69
|
+
*
|
|
70
|
+
* @param search - the search query
|
|
71
|
+
* @param data - the collection to search
|
|
72
|
+
* @param options - `fuseOptions` (forwarded to `new Fuse()`), `resultLimit`,
|
|
73
|
+
* `matchAllWhenSearchEmpty`
|
|
74
|
+
*
|
|
75
|
+
* @__NO_SIDE_EFFECTS__
|
|
76
|
+
* @example
|
|
77
|
+
* const { fuse, results } = useFuse(input, data, {
|
|
78
|
+
* fuseOptions: { keys: ['firstName', 'lastName'] },
|
|
79
|
+
* resultLimit: 10,
|
|
80
|
+
* matchAllWhenSearchEmpty: true,
|
|
81
|
+
* })
|
|
82
|
+
* results[0].item // the best match
|
|
83
|
+
* fuse.search('john') // search the same index directly
|
|
84
|
+
*/
|
|
85
|
+
export declare function useFuse<DataItem>(search: string, data: readonly DataItem[], options?: RefOrValue<UseFuseOptions<DataItem>>): UseFuseReturn<DataItem>;
|
|
86
|
+
//#endregion
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
(function(exports, _reause_shared, fuse_js, react) {
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
//#region \0rolldown/runtime.js
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
21
|
+
value: mod,
|
|
22
|
+
enumerable: true
|
|
23
|
+
}) : target, mod));
|
|
24
|
+
//#endregion
|
|
25
|
+
fuse_js = __toESM(fuse_js, 1);
|
|
26
|
+
//#region useFuse/index.tsx
|
|
27
|
+
/**
|
|
28
|
+
* React port of VueUse's `useFuse` — easily implement fuzzy search with
|
|
29
|
+
* [Fuse.js](https://github.com/krisk/fuse).
|
|
30
|
+
*
|
|
31
|
+
* Map from @vueuse/integrations `useFuse`
|
|
32
|
+
* (`source/vueuse/packages/integrations/useFuse/`), a reactive wrapper around
|
|
33
|
+
* a `Fuse` instance. `search` and `data` are the hook's **read-only value
|
|
34
|
+
* sources** and take plain values (`string` and `readonly DataItem[]`; upstream:
|
|
35
|
+
* `MaybeRefOrGetter`). `options` stays `RefOrValue` (a config object, upstream
|
|
36
|
+
* `MaybeRefOrGetter`).
|
|
37
|
+
*
|
|
38
|
+
* Adjustment for React:
|
|
39
|
+
* - upstream returns `{ fuse: Ref<Fuse>, results: ComputedRef<FuseResult[]> }`;
|
|
40
|
+
* here both are plain values read during render — `fuse` is the `Fuse`
|
|
41
|
+
* instance itself (no `.value`), `results` is a plain array;
|
|
42
|
+
* - upstream rebuilds the index in `watch(() => toValue(options)?.fuseOptions,
|
|
43
|
+
* …, { deep: true })` and refreshes the collection in `watch(() => toValue(data), …)`.
|
|
44
|
+
* React has no deep watcher, and serializing `fuseOptions` to compare them by
|
|
45
|
+
* value would break function-valued options (`sortFn`, `getFn`, `keys[].getFn`),
|
|
46
|
+
* so the `Fuse` instance is memoized on the identity of the `data`
|
|
47
|
+
* array and of `fuseOptions` instead: pass a NEW array reference when the data
|
|
48
|
+
* changes, and a memoized `fuseOptions` object for best performance. Mutating
|
|
49
|
+
* the data array in place is not detected (upstream's deep watch was);
|
|
50
|
+
* - `results` is memoized on the search string and the `data` identity, so a
|
|
51
|
+
* changed `search`/`data` prop recomputes on the next render;
|
|
52
|
+
* - `options` is NOT widened: it is a config object (upstream
|
|
53
|
+
* `MaybeRefOrGetter`, a maintainer decision), so a plain options object, a
|
|
54
|
+
* ref-like `{ current }` object or a getter are the accepted forms.
|
|
55
|
+
*
|
|
56
|
+
* @param search - the search query
|
|
57
|
+
* @param data - the collection to search
|
|
58
|
+
* @param options - `fuseOptions` (forwarded to `new Fuse()`), `resultLimit`,
|
|
59
|
+
* `matchAllWhenSearchEmpty`
|
|
60
|
+
*
|
|
61
|
+
* @__NO_SIDE_EFFECTS__
|
|
62
|
+
* @example
|
|
63
|
+
* const { fuse, results } = useFuse(input, data, {
|
|
64
|
+
* fuseOptions: { keys: ['firstName', 'lastName'] },
|
|
65
|
+
* resultLimit: 10,
|
|
66
|
+
* matchAllWhenSearchEmpty: true,
|
|
67
|
+
* })
|
|
68
|
+
* results[0].item // the best match
|
|
69
|
+
* fuse.search('john') // search the same index directly
|
|
70
|
+
*/
|
|
71
|
+
function useFuse(search, data, options) {
|
|
72
|
+
const dataValue = data;
|
|
73
|
+
const optionsValue = (0, _reause_shared.toValue)(options);
|
|
74
|
+
const fuse = (0, react.useMemo)(() => new fuse_js.default(dataValue, optionsValue === null || optionsValue === void 0 ? void 0 : optionsValue.fuseOptions), [dataValue, optionsValue === null || optionsValue === void 0 ? void 0 : optionsValue.fuseOptions]);
|
|
75
|
+
const searchValue = search;
|
|
76
|
+
return {
|
|
77
|
+
fuse,
|
|
78
|
+
results: (0, react.useMemo)(() => {
|
|
79
|
+
if ((optionsValue === null || optionsValue === void 0 ? void 0 : optionsValue.matchAllWhenSearchEmpty) && !searchValue) return dataValue.map((item, index) => ({
|
|
80
|
+
item,
|
|
81
|
+
refIndex: index
|
|
82
|
+
}));
|
|
83
|
+
const limit = optionsValue === null || optionsValue === void 0 ? void 0 : optionsValue.resultLimit;
|
|
84
|
+
return fuse.search(searchValue, limit ? { limit } : void 0);
|
|
85
|
+
}, [
|
|
86
|
+
dataValue,
|
|
87
|
+
fuse,
|
|
88
|
+
optionsValue,
|
|
89
|
+
searchValue
|
|
90
|
+
])
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
exports.useFuse = useFuse;
|
|
95
|
+
})(this.reause = this.reause || {}, reause, Fuse, React);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t,n,r){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var i=Object.create,a=Object.defineProperty,o=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,c=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty,u=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=s(t),c=0,u=i.length,d;c<u;c++)d=i[c],!l.call(e,d)&&d!==n&&a(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=o(t,d))||r.enumerable});return e};n=((e,t,n)=>(n=e==null?{}:i(c(e)),u(t||!e||!e.__esModule||!l.call(e,`default`)?a(n,`default`,{value:e,enumerable:!0}):n,e)))(n,1);function d(e,i,a){let o=i,s=(0,t.toValue)(a),c=(0,r.useMemo)(()=>new n.default(o,s==null?void 0:s.fuseOptions),[o,s==null?void 0:s.fuseOptions]),l=e;return{fuse:c,results:(0,r.useMemo)(()=>{if(s!=null&&s.matchAllWhenSearchEmpty&&!l)return o.map((e,t)=>({item:e,refIndex:t}));let e=s==null?void 0:s.resultLimit;return c.search(l,e?{limit:e}:void 0)},[o,c,s,l])}}e.useFuse=d})(this.reause=this.reause||{},reause,Fuse,React);
|
package/dist/useFuse.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { toValue } from "@reause/shared";
|
|
3
|
+
import Fuse from "fuse.js";
|
|
4
|
+
//#region useFuse/index.tsx
|
|
5
|
+
/**
|
|
6
|
+
* React port of VueUse's `useFuse` — easily implement fuzzy search with
|
|
7
|
+
* [Fuse.js](https://github.com/krisk/fuse).
|
|
8
|
+
*
|
|
9
|
+
* Map from @vueuse/integrations `useFuse`
|
|
10
|
+
* (`source/vueuse/packages/integrations/useFuse/`), a reactive wrapper around
|
|
11
|
+
* a `Fuse` instance. `search` and `data` are the hook's **read-only value
|
|
12
|
+
* sources** and take plain values (`string` and `readonly DataItem[]`; upstream:
|
|
13
|
+
* `MaybeRefOrGetter`). `options` stays `RefOrValue` (a config object, upstream
|
|
14
|
+
* `MaybeRefOrGetter`).
|
|
15
|
+
*
|
|
16
|
+
* Adjustment for React:
|
|
17
|
+
* - upstream returns `{ fuse: Ref<Fuse>, results: ComputedRef<FuseResult[]> }`;
|
|
18
|
+
* here both are plain values read during render — `fuse` is the `Fuse`
|
|
19
|
+
* instance itself (no `.value`), `results` is a plain array;
|
|
20
|
+
* - upstream rebuilds the index in `watch(() => toValue(options)?.fuseOptions,
|
|
21
|
+
* …, { deep: true })` and refreshes the collection in `watch(() => toValue(data), …)`.
|
|
22
|
+
* React has no deep watcher, and serializing `fuseOptions` to compare them by
|
|
23
|
+
* value would break function-valued options (`sortFn`, `getFn`, `keys[].getFn`),
|
|
24
|
+
* so the `Fuse` instance is memoized on the identity of the `data`
|
|
25
|
+
* array and of `fuseOptions` instead: pass a NEW array reference when the data
|
|
26
|
+
* changes, and a memoized `fuseOptions` object for best performance. Mutating
|
|
27
|
+
* the data array in place is not detected (upstream's deep watch was);
|
|
28
|
+
* - `results` is memoized on the search string and the `data` identity, so a
|
|
29
|
+
* changed `search`/`data` prop recomputes on the next render;
|
|
30
|
+
* - `options` is NOT widened: it is a config object (upstream
|
|
31
|
+
* `MaybeRefOrGetter`, a maintainer decision), so a plain options object, a
|
|
32
|
+
* ref-like `{ current }` object or a getter are the accepted forms.
|
|
33
|
+
*
|
|
34
|
+
* @param search - the search query
|
|
35
|
+
* @param data - the collection to search
|
|
36
|
+
* @param options - `fuseOptions` (forwarded to `new Fuse()`), `resultLimit`,
|
|
37
|
+
* `matchAllWhenSearchEmpty`
|
|
38
|
+
*
|
|
39
|
+
* @__NO_SIDE_EFFECTS__
|
|
40
|
+
* @example
|
|
41
|
+
* const { fuse, results } = useFuse(input, data, {
|
|
42
|
+
* fuseOptions: { keys: ['firstName', 'lastName'] },
|
|
43
|
+
* resultLimit: 10,
|
|
44
|
+
* matchAllWhenSearchEmpty: true,
|
|
45
|
+
* })
|
|
46
|
+
* results[0].item // the best match
|
|
47
|
+
* fuse.search('john') // search the same index directly
|
|
48
|
+
*/
|
|
49
|
+
function useFuse(search, data, options) {
|
|
50
|
+
const dataValue = data;
|
|
51
|
+
const optionsValue = toValue(options);
|
|
52
|
+
const fuse = useMemo(() => new Fuse(dataValue, optionsValue === null || optionsValue === void 0 ? void 0 : optionsValue.fuseOptions), [dataValue, optionsValue === null || optionsValue === void 0 ? void 0 : optionsValue.fuseOptions]);
|
|
53
|
+
const searchValue = search;
|
|
54
|
+
return {
|
|
55
|
+
fuse,
|
|
56
|
+
results: useMemo(() => {
|
|
57
|
+
if ((optionsValue === null || optionsValue === void 0 ? void 0 : optionsValue.matchAllWhenSearchEmpty) && !searchValue) return dataValue.map((item, index) => ({
|
|
58
|
+
item,
|
|
59
|
+
refIndex: index
|
|
60
|
+
}));
|
|
61
|
+
const limit = optionsValue === null || optionsValue === void 0 ? void 0 : optionsValue.resultLimit;
|
|
62
|
+
return fuse.search(searchValue, limit ? { limit } : void 0);
|
|
63
|
+
}, [
|
|
64
|
+
dataValue,
|
|
65
|
+
fuse,
|
|
66
|
+
optionsValue,
|
|
67
|
+
searchValue
|
|
68
|
+
])
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { useFuse };
|