@tale-ui/utils 0.0.3
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/CHANGELOG.md +14 -0
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/detectBrowser.d.ts +8 -0
- package/detectBrowser.js +64 -0
- package/empty.d.ts +3 -0
- package/empty.js +10 -0
- package/error.d.ts +2 -0
- package/error.js +23 -0
- package/esm/detectBrowser.d.ts +8 -0
- package/esm/detectBrowser.js +58 -0
- package/esm/empty.d.ts +3 -0
- package/esm/empty.js +3 -0
- package/esm/error.d.ts +2 -0
- package/esm/error.js +16 -0
- package/esm/fastHooks.d.ts +14 -0
- package/esm/fastHooks.js +43 -0
- package/esm/fastObjectShallowCompare.d.ts +1 -0
- package/esm/fastObjectShallowCompare.js +29 -0
- package/esm/formatErrorMessage.d.ts +18 -0
- package/esm/formatErrorMessage.js +26 -0
- package/esm/generateId.d.ts +1 -0
- package/esm/generateId.js +5 -0
- package/esm/getReactElementRef.d.ts +5 -0
- package/esm/getReactElementRef.js +14 -0
- package/esm/inertValue.d.ts +1 -0
- package/esm/inertValue.js +8 -0
- package/esm/isElementDisabled.d.ts +1 -0
- package/esm/isElementDisabled.js +3 -0
- package/esm/isMouseWithinBounds.d.ts +1 -0
- package/esm/isMouseWithinBounds.js +10 -0
- package/esm/mergeObjects.d.ts +1 -0
- package/esm/mergeObjects.js +15 -0
- package/esm/owner.d.ts +2 -0
- package/esm/owner.js +4 -0
- package/esm/package.json +1 -0
- package/esm/reactVersion.d.ts +3 -0
- package/esm/reactVersion.js +5 -0
- package/esm/safeReact.d.ts +2 -0
- package/esm/safeReact.js +6 -0
- package/esm/store/ReactStore.d.ts +91 -0
- package/esm/store/ReactStore.js +199 -0
- package/esm/store/Store.d.ts +58 -0
- package/esm/store/Store.js +111 -0
- package/esm/store/StoreInspector.d.ts +41 -0
- package/esm/store/StoreInspector.js +537 -0
- package/esm/store/createSelector.d.ts +30 -0
- package/esm/store/createSelector.js +148 -0
- package/esm/store/index.d.ts +5 -0
- package/esm/store/index.js +5 -0
- package/esm/store/useStore.d.ts +22 -0
- package/esm/store/useStore.js +107 -0
- package/esm/testUtils.d.ts +17 -0
- package/esm/testUtils.js +19 -0
- package/esm/useAnimationFrame.d.ts +18 -0
- package/esm/useAnimationFrame.js +106 -0
- package/esm/useControlled.d.ts +24 -0
- package/esm/useControlled.js +40 -0
- package/esm/useEnhancedClickHandler.d.ts +13 -0
- package/esm/useEnhancedClickHandler.js +38 -0
- package/esm/useForcedRerendering.d.ts +4 -0
- package/esm/useForcedRerendering.js +13 -0
- package/esm/useId.d.ts +7 -0
- package/esm/useId.js +41 -0
- package/esm/useInterval.d.ts +13 -0
- package/esm/useInterval.js +36 -0
- package/esm/useIsoLayoutEffect.d.ts +2 -0
- package/esm/useIsoLayoutEffect.js +5 -0
- package/esm/useMergedRefs.d.ts +21 -0
- package/esm/useMergedRefs.js +108 -0
- package/esm/useOnFirstRender.d.ts +1 -0
- package/esm/useOnFirstRender.js +10 -0
- package/esm/useOnMount.d.ts +5 -0
- package/esm/useOnMount.js +14 -0
- package/esm/usePreviousValue.d.ts +6 -0
- package/esm/usePreviousValue.js +22 -0
- package/esm/useRefWithInit.d.ts +10 -0
- package/esm/useRefWithInit.js +20 -0
- package/esm/useScrollLock.d.ts +7 -0
- package/esm/useScrollLock.js +244 -0
- package/esm/useStableCallback.d.ts +13 -0
- package/esm/useStableCallback.js +44 -0
- package/esm/useTimeout.d.ts +17 -0
- package/esm/useTimeout.js +43 -0
- package/esm/useValueAsRef.d.ts +10 -0
- package/esm/useValueAsRef.js +28 -0
- package/esm/visuallyHidden.d.ts +3 -0
- package/esm/visuallyHidden.js +20 -0
- package/esm/warn.d.ts +1 -0
- package/esm/warn.js +13 -0
- package/fastHooks.d.ts +14 -0
- package/fastHooks.js +54 -0
- package/fastObjectShallowCompare.d.ts +1 -0
- package/fastObjectShallowCompare.js +35 -0
- package/formatErrorMessage.d.ts +18 -0
- package/formatErrorMessage.js +33 -0
- package/generateId.d.ts +1 -0
- package/generateId.js +11 -0
- package/getReactElementRef.d.ts +5 -0
- package/getReactElementRef.js +20 -0
- package/inertValue.d.ts +1 -0
- package/inertValue.js +14 -0
- package/isElementDisabled.d.ts +1 -0
- package/isElementDisabled.js +9 -0
- package/isMouseWithinBounds.d.ts +1 -0
- package/isMouseWithinBounds.js +16 -0
- package/mergeObjects.d.ts +1 -0
- package/mergeObjects.js +21 -0
- package/owner.d.ts +2 -0
- package/owner.js +16 -0
- package/package.json +64 -0
- package/reactVersion.d.ts +3 -0
- package/reactVersion.js +12 -0
- package/safeReact.d.ts +2 -0
- package/safeReact.js +12 -0
- package/store/ReactStore.d.ts +91 -0
- package/store/ReactStore.js +205 -0
- package/store/Store.d.ts +58 -0
- package/store/Store.js +118 -0
- package/store/StoreInspector.d.ts +41 -0
- package/store/StoreInspector.js +544 -0
- package/store/createSelector.d.ts +30 -0
- package/store/createSelector.js +154 -0
- package/store/index.d.ts +5 -0
- package/store/index.js +60 -0
- package/store/useStore.d.ts +22 -0
- package/store/useStore.js +115 -0
- package/testUtils.d.ts +17 -0
- package/testUtils.js +26 -0
- package/useAnimationFrame.d.ts +18 -0
- package/useAnimationFrame.js +113 -0
- package/useControlled.d.ts +24 -0
- package/useControlled.js +46 -0
- package/useEnhancedClickHandler.d.ts +13 -0
- package/useEnhancedClickHandler.js +44 -0
- package/useForcedRerendering.d.ts +4 -0
- package/useForcedRerendering.js +18 -0
- package/useId.d.ts +7 -0
- package/useId.js +47 -0
- package/useInterval.d.ts +13 -0
- package/useInterval.js +43 -0
- package/useIsoLayoutEffect.d.ts +2 -0
- package/useIsoLayoutEffect.js +11 -0
- package/useMergedRefs.d.ts +21 -0
- package/useMergedRefs.js +114 -0
- package/useOnFirstRender.d.ts +1 -0
- package/useOnFirstRender.js +16 -0
- package/useOnMount.d.ts +5 -0
- package/useOnMount.js +20 -0
- package/usePreviousValue.d.ts +6 -0
- package/usePreviousValue.js +27 -0
- package/useRefWithInit.d.ts +10 -0
- package/useRefWithInit.js +26 -0
- package/useScrollLock.d.ts +7 -0
- package/useScrollLock.js +249 -0
- package/useStableCallback.d.ts +13 -0
- package/useStableCallback.js +49 -0
- package/useTimeout.d.ts +17 -0
- package/useTimeout.js +50 -0
- package/useValueAsRef.d.ts +10 -0
- package/useValueAsRef.js +32 -0
- package/visuallyHidden.d.ts +3 -0
- package/visuallyHidden.js +26 -0
- package/warn.d.ts +1 -0
- package/warn.js +19 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createSelectorMemoized = exports.createSelector = void 0;
|
|
7
|
+
var _reselect = require("reselect");
|
|
8
|
+
/* eslint-disable no-underscore-dangle */ // __cacheKey__
|
|
9
|
+
|
|
10
|
+
const reselectCreateSelector = (0, _reselect.createSelectorCreator)({
|
|
11
|
+
memoize: _reselect.lruMemoize,
|
|
12
|
+
memoizeOptions: {
|
|
13
|
+
maxSize: 1,
|
|
14
|
+
equalityCheck: Object.is
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Creates a selector function that can be used to derive values from the store's state.
|
|
19
|
+
* The selector can take up to three additional arguments that can be used in the selector logic.
|
|
20
|
+
* This function accepts up to six functions and combines them into a single selector function.
|
|
21
|
+
* The last parameter is the combiner function that combines the results of the previous selectors.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const selector = createSelector(
|
|
25
|
+
* (state) => state.disabled
|
|
26
|
+
* );
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const selector = createSelector(
|
|
30
|
+
* (state) => state.disabled,
|
|
31
|
+
* (state) => state.open,
|
|
32
|
+
* (disabled, open) => ({ disabled, open })
|
|
33
|
+
* );
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
/* eslint-disable id-denylist */
|
|
37
|
+
const createSelector = (a, b, c, d, e, f, ...other) => {
|
|
38
|
+
if (other.length > 0) {
|
|
39
|
+
throw /* FIXME (minify-errors-in-prod): Unminified error message in production build! */new Error('Unsupported number of selectors');
|
|
40
|
+
}
|
|
41
|
+
let selector;
|
|
42
|
+
if (a && b && c && d && e && f) {
|
|
43
|
+
selector = (state, a1, a2, a3) => {
|
|
44
|
+
const va = a(state, a1, a2, a3);
|
|
45
|
+
const vb = b(state, a1, a2, a3);
|
|
46
|
+
const vc = c(state, a1, a2, a3);
|
|
47
|
+
const vd = d(state, a1, a2, a3);
|
|
48
|
+
const ve = e(state, a1, a2, a3);
|
|
49
|
+
return f(va, vb, vc, vd, ve, a1, a2, a3);
|
|
50
|
+
};
|
|
51
|
+
} else if (a && b && c && d && e) {
|
|
52
|
+
selector = (state, a1, a2, a3) => {
|
|
53
|
+
const va = a(state, a1, a2, a3);
|
|
54
|
+
const vb = b(state, a1, a2, a3);
|
|
55
|
+
const vc = c(state, a1, a2, a3);
|
|
56
|
+
const vd = d(state, a1, a2, a3);
|
|
57
|
+
return e(va, vb, vc, vd, a1, a2, a3);
|
|
58
|
+
};
|
|
59
|
+
} else if (a && b && c && d) {
|
|
60
|
+
selector = (state, a1, a2, a3) => {
|
|
61
|
+
const va = a(state, a1, a2, a3);
|
|
62
|
+
const vb = b(state, a1, a2, a3);
|
|
63
|
+
const vc = c(state, a1, a2, a3);
|
|
64
|
+
return d(va, vb, vc, a1, a2, a3);
|
|
65
|
+
};
|
|
66
|
+
} else if (a && b && c) {
|
|
67
|
+
selector = (state, a1, a2, a3) => {
|
|
68
|
+
const va = a(state, a1, a2, a3);
|
|
69
|
+
const vb = b(state, a1, a2, a3);
|
|
70
|
+
return c(va, vb, a1, a2, a3);
|
|
71
|
+
};
|
|
72
|
+
} else if (a && b) {
|
|
73
|
+
selector = (state, a1, a2, a3) => {
|
|
74
|
+
const va = a(state, a1, a2, a3);
|
|
75
|
+
return b(va, a1, a2, a3);
|
|
76
|
+
};
|
|
77
|
+
} else if (a) {
|
|
78
|
+
selector = a;
|
|
79
|
+
} else {
|
|
80
|
+
throw /* minify-error-disabled */new Error('Missing arguments');
|
|
81
|
+
}
|
|
82
|
+
return selector;
|
|
83
|
+
};
|
|
84
|
+
/* eslint-enable id-denylist */
|
|
85
|
+
exports.createSelector = createSelector;
|
|
86
|
+
const createSelectorMemoized = (...selectors) => {
|
|
87
|
+
const cache = new WeakMap();
|
|
88
|
+
let nextCacheId = 1;
|
|
89
|
+
const combiner = selectors[selectors.length - 1];
|
|
90
|
+
const nSelectors = selectors.length - 1 || 1;
|
|
91
|
+
// (s1, s2, ..., sN, a1, a2, a3) => { ... }
|
|
92
|
+
const argsLength = combiner.length - nSelectors;
|
|
93
|
+
if (argsLength > 3) {
|
|
94
|
+
throw /* FIXME (minify-errors-in-prod): Unminified error message in production build! */new Error('Unsupported number of arguments');
|
|
95
|
+
}
|
|
96
|
+
const selector = (state, a1, a2, a3) => {
|
|
97
|
+
let cacheKey = state.__cacheKey__;
|
|
98
|
+
if (!cacheKey) {
|
|
99
|
+
cacheKey = {
|
|
100
|
+
id: nextCacheId
|
|
101
|
+
};
|
|
102
|
+
state.__cacheKey__ = cacheKey;
|
|
103
|
+
nextCacheId += 1;
|
|
104
|
+
}
|
|
105
|
+
let fn = cache.get(cacheKey);
|
|
106
|
+
if (!fn) {
|
|
107
|
+
let reselectArgs = selectors;
|
|
108
|
+
const selectorArgs = [undefined, undefined, undefined];
|
|
109
|
+
switch (argsLength) {
|
|
110
|
+
case 0:
|
|
111
|
+
break;
|
|
112
|
+
case 1:
|
|
113
|
+
{
|
|
114
|
+
reselectArgs = [...selectors.slice(0, -1), () => selectorArgs[0], combiner];
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case 2:
|
|
118
|
+
{
|
|
119
|
+
reselectArgs = [...selectors.slice(0, -1), () => selectorArgs[0], () => selectorArgs[1], combiner];
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
case 3:
|
|
123
|
+
{
|
|
124
|
+
reselectArgs = [...selectors.slice(0, -1), () => selectorArgs[0], () => selectorArgs[1], () => selectorArgs[2], combiner];
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
default:
|
|
128
|
+
throw /* FIXME (minify-errors-in-prod): Unminified error message in production build! */new Error('Unsupported number of arguments');
|
|
129
|
+
}
|
|
130
|
+
fn = reselectCreateSelector(...reselectArgs);
|
|
131
|
+
fn.selectorArgs = selectorArgs;
|
|
132
|
+
cache.set(cacheKey, fn);
|
|
133
|
+
}
|
|
134
|
+
fn.selectorArgs[0] = a1;
|
|
135
|
+
fn.selectorArgs[1] = a2;
|
|
136
|
+
fn.selectorArgs[2] = a3;
|
|
137
|
+
|
|
138
|
+
// prettier-ignore
|
|
139
|
+
switch (argsLength) {
|
|
140
|
+
case 0:
|
|
141
|
+
return fn(state);
|
|
142
|
+
case 1:
|
|
143
|
+
return fn(state, a1);
|
|
144
|
+
case 2:
|
|
145
|
+
return fn(state, a1, a2);
|
|
146
|
+
case 3:
|
|
147
|
+
return fn(state, a1, a2, a3);
|
|
148
|
+
default:
|
|
149
|
+
throw /* minify-error-disabled */new Error('unreachable');
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
return selector;
|
|
153
|
+
};
|
|
154
|
+
exports.createSelectorMemoized = createSelectorMemoized;
|
package/store/index.d.ts
ADDED
package/store/index.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _createSelector = require("./createSelector");
|
|
7
|
+
Object.keys(_createSelector).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _createSelector[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _createSelector[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
var _useStore = require("./useStore");
|
|
18
|
+
Object.keys(_useStore).forEach(function (key) {
|
|
19
|
+
if (key === "default" || key === "__esModule") return;
|
|
20
|
+
if (key in exports && exports[key] === _useStore[key]) return;
|
|
21
|
+
Object.defineProperty(exports, key, {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () {
|
|
24
|
+
return _useStore[key];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
var _Store = require("./Store");
|
|
29
|
+
Object.keys(_Store).forEach(function (key) {
|
|
30
|
+
if (key === "default" || key === "__esModule") return;
|
|
31
|
+
if (key in exports && exports[key] === _Store[key]) return;
|
|
32
|
+
Object.defineProperty(exports, key, {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () {
|
|
35
|
+
return _Store[key];
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
var _ReactStore = require("./ReactStore");
|
|
40
|
+
Object.keys(_ReactStore).forEach(function (key) {
|
|
41
|
+
if (key === "default" || key === "__esModule") return;
|
|
42
|
+
if (key in exports && exports[key] === _ReactStore[key]) return;
|
|
43
|
+
Object.defineProperty(exports, key, {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: function () {
|
|
46
|
+
return _ReactStore[key];
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
var _StoreInspector = require("./StoreInspector");
|
|
51
|
+
Object.keys(_StoreInspector).forEach(function (key) {
|
|
52
|
+
if (key === "default" || key === "__esModule") return;
|
|
53
|
+
if (key in exports && exports[key] === _StoreInspector[key]) return;
|
|
54
|
+
Object.defineProperty(exports, key, {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _StoreInspector[key];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Instance } from "../fastHooks.js";
|
|
2
|
+
import type { ReadonlyStore } from "./Store.js";
|
|
3
|
+
export declare function useStore<State, Value>(store: ReadonlyStore<State>, selector: (state: State) => Value): Value;
|
|
4
|
+
export declare function useStore<State, Value, A1>(store: ReadonlyStore<State>, selector: (state: State, a1: A1) => Value, a1: A1): Value;
|
|
5
|
+
export declare function useStore<State, Value, A1, A2>(store: ReadonlyStore<State>, selector: (state: State, a1: A1, a2: A2) => Value, a1: A1, a2: A2): Value;
|
|
6
|
+
export declare function useStore<State, Value, A1, A2, A3>(store: ReadonlyStore<State>, selector: (state: State, a1: A1, a2: A2, a3: A3) => Value, a1: A1, a2: A2, a3: A3): Value;
|
|
7
|
+
export type StoreInstance = Instance & {
|
|
8
|
+
syncIndex: number;
|
|
9
|
+
syncTick: number;
|
|
10
|
+
syncHooks: {
|
|
11
|
+
store: any;
|
|
12
|
+
selector: Function;
|
|
13
|
+
a1: unknown;
|
|
14
|
+
a2: unknown;
|
|
15
|
+
a3: unknown;
|
|
16
|
+
value: unknown;
|
|
17
|
+
didChange: boolean;
|
|
18
|
+
}[];
|
|
19
|
+
didChangeStore: boolean;
|
|
20
|
+
subscribe: (onStoreChange: any) => () => void;
|
|
21
|
+
getSnapshot: () => unknown;
|
|
22
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.useStore = useStore;
|
|
8
|
+
var React = _interopRequireWildcard(require("react"));
|
|
9
|
+
var _shim = require("use-sync-external-store/shim");
|
|
10
|
+
var _withSelector = require("use-sync-external-store/shim/with-selector");
|
|
11
|
+
var _reactVersion = require("../reactVersion");
|
|
12
|
+
var _fastHooks = require("../fastHooks");
|
|
13
|
+
/* We need to import the shim because React 17 does not support the `useSyncExternalStore` API.
|
|
14
|
+
* More info: https://github.com/mui/mui-x/issues/18303#issuecomment-2958392341 */
|
|
15
|
+
|
|
16
|
+
/* Some tests fail in R18 with the raw useSyncExternalStore. It may be possible to make it work
|
|
17
|
+
* but for now we only enable it for R19+. */
|
|
18
|
+
const canUseRawUseSyncExternalStore = (0, _reactVersion.isReactVersionAtLeast)(19);
|
|
19
|
+
const useStoreImplementation = canUseRawUseSyncExternalStore ? useStoreFast : useStoreLegacy;
|
|
20
|
+
function useStore(store, selector, a1, a2, a3) {
|
|
21
|
+
return useStoreImplementation(store, selector, a1, a2, a3);
|
|
22
|
+
}
|
|
23
|
+
function useStoreR19(store, selector, a1, a2, a3) {
|
|
24
|
+
const getSelection = React.useCallback(() => selector(store.getSnapshot(), a1, a2, a3), [store, selector, a1, a2, a3]);
|
|
25
|
+
return (0, _shim.useSyncExternalStore)(store.subscribe, getSelection, getSelection);
|
|
26
|
+
}
|
|
27
|
+
(0, _fastHooks.register)({
|
|
28
|
+
before(instance) {
|
|
29
|
+
instance.syncIndex = 0;
|
|
30
|
+
if (!instance.didInitialize) {
|
|
31
|
+
instance.syncTick = 1;
|
|
32
|
+
instance.syncHooks = [];
|
|
33
|
+
instance.didChangeStore = true;
|
|
34
|
+
instance.getSnapshot = () => {
|
|
35
|
+
let didChange = false;
|
|
36
|
+
for (let i = 0; i < instance.syncHooks.length; i += 1) {
|
|
37
|
+
const hook = instance.syncHooks[i];
|
|
38
|
+
const value = hook.selector(hook.store.state, hook.a1, hook.a2, hook.a3);
|
|
39
|
+
if (hook.didChange || !Object.is(hook.value, value)) {
|
|
40
|
+
didChange = true;
|
|
41
|
+
hook.value = value;
|
|
42
|
+
hook.didChange = false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (didChange) {
|
|
46
|
+
instance.syncTick += 1;
|
|
47
|
+
}
|
|
48
|
+
return instance.syncTick;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
after(instance) {
|
|
53
|
+
if (instance.syncHooks.length > 0) {
|
|
54
|
+
if (instance.didChangeStore) {
|
|
55
|
+
instance.didChangeStore = false;
|
|
56
|
+
instance.subscribe = onStoreChange => {
|
|
57
|
+
const stores = new Set();
|
|
58
|
+
for (const hook of instance.syncHooks) {
|
|
59
|
+
stores.add(hook.store);
|
|
60
|
+
}
|
|
61
|
+
const unsubscribes = [];
|
|
62
|
+
for (const store of stores) {
|
|
63
|
+
unsubscribes.push(store.subscribe(onStoreChange));
|
|
64
|
+
}
|
|
65
|
+
return () => {
|
|
66
|
+
for (const unsubscribe of unsubscribes) {
|
|
67
|
+
unsubscribe();
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
73
|
+
(0, _shim.useSyncExternalStore)(instance.subscribe, instance.getSnapshot, instance.getSnapshot);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
function useStoreFast(store, selector, a1, a2, a3) {
|
|
78
|
+
const instance = (0, _fastHooks.getInstance)();
|
|
79
|
+
if (!instance) {
|
|
80
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
81
|
+
return useStoreR19(store, selector, a1, a2, a3);
|
|
82
|
+
}
|
|
83
|
+
const index = instance.syncIndex;
|
|
84
|
+
instance.syncIndex += 1;
|
|
85
|
+
let hook;
|
|
86
|
+
if (!instance.didInitialize) {
|
|
87
|
+
hook = {
|
|
88
|
+
store,
|
|
89
|
+
selector,
|
|
90
|
+
a1,
|
|
91
|
+
a2,
|
|
92
|
+
a3,
|
|
93
|
+
value: selector(store.getSnapshot(), a1, a2, a3),
|
|
94
|
+
didChange: false
|
|
95
|
+
};
|
|
96
|
+
instance.syncHooks.push(hook);
|
|
97
|
+
} else {
|
|
98
|
+
hook = instance.syncHooks[index];
|
|
99
|
+
if (hook.store !== store || hook.selector !== selector || !Object.is(hook.a1, a1) || !Object.is(hook.a2, a2) || !Object.is(hook.a3, a3)) {
|
|
100
|
+
if (hook.store !== store) {
|
|
101
|
+
instance.didChangeStore = true;
|
|
102
|
+
}
|
|
103
|
+
hook.store = store;
|
|
104
|
+
hook.selector = selector;
|
|
105
|
+
hook.a1 = a1;
|
|
106
|
+
hook.a2 = a2;
|
|
107
|
+
hook.a3 = a3;
|
|
108
|
+
hook.didChange = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return hook.value;
|
|
112
|
+
}
|
|
113
|
+
function useStoreLegacy(store, selector, a1, a2, a3) {
|
|
114
|
+
return (0, _withSelector.useSyncExternalStoreWithSelector)(store.subscribe, store.getSnapshot, store.getSnapshot, state => selector(state, a1, a2, a3));
|
|
115
|
+
}
|
package/testUtils.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the test runs in JSDOM environment
|
|
3
|
+
*/
|
|
4
|
+
export declare const isJSDOM: boolean;
|
|
5
|
+
export type IfEquals<T, U, Y = unknown, N = never> = (<G>() => G extends T ? 1 : 2) extends (<G>() => G extends U ? 1 : 2) ? Y : N;
|
|
6
|
+
/**
|
|
7
|
+
* Issues a type error if `Expected` is not identical to `Actual`.
|
|
8
|
+
*
|
|
9
|
+
* `Expected` should be declared when invoking `expectType`.
|
|
10
|
+
* `Actual` should almost always we be a `typeof value` statement.
|
|
11
|
+
*
|
|
12
|
+
* @example `expectType<number | string, typeof value>(value)`
|
|
13
|
+
* TypeScript issues a type error since `value is not assignable to never`.
|
|
14
|
+
* This means `typeof value` is not identical to `number | string`
|
|
15
|
+
* @param _actual
|
|
16
|
+
*/
|
|
17
|
+
export declare function expectType<Expected, Actual>(_actual: IfEquals<Actual, Expected, Actual>): void;
|
package/testUtils.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.expectType = expectType;
|
|
7
|
+
exports.isJSDOM = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Whether the test runs in JSDOM environment
|
|
10
|
+
*/
|
|
11
|
+
const isJSDOM = exports.isJSDOM = /jsdom/.test(window.navigator.userAgent);
|
|
12
|
+
|
|
13
|
+
// https://stackoverflow.com/questions/53807517/how-to-test-if-two-types-are-exactly-the-same
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Issues a type error if `Expected` is not identical to `Actual`.
|
|
17
|
+
*
|
|
18
|
+
* `Expected` should be declared when invoking `expectType`.
|
|
19
|
+
* `Actual` should almost always we be a `typeof value` statement.
|
|
20
|
+
*
|
|
21
|
+
* @example `expectType<number | string, typeof value>(value)`
|
|
22
|
+
* TypeScript issues a type error since `value is not assignable to never`.
|
|
23
|
+
* This means `typeof value` is not identical to `number | string`
|
|
24
|
+
* @param _actual
|
|
25
|
+
*/
|
|
26
|
+
function expectType(_actual) {}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type AnimationFrameId = number;
|
|
2
|
+
export declare class AnimationFrame {
|
|
3
|
+
static create(): AnimationFrame;
|
|
4
|
+
static request(fn: FrameRequestCallback): number;
|
|
5
|
+
static cancel(id: AnimationFrameId): void;
|
|
6
|
+
currentId: AnimationFrameId | null;
|
|
7
|
+
/**
|
|
8
|
+
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
9
|
+
*/
|
|
10
|
+
request(fn: Function): void;
|
|
11
|
+
cancel: () => void;
|
|
12
|
+
disposeEffect: () => () => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A `requestAnimationFrame` with automatic cleanup and guard.
|
|
16
|
+
*/
|
|
17
|
+
export declare function useAnimationFrame(): AnimationFrame;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.AnimationFrame = void 0;
|
|
8
|
+
exports.useAnimationFrame = useAnimationFrame;
|
|
9
|
+
var _useRefWithInit = require("./useRefWithInit");
|
|
10
|
+
var _useOnMount = require("./useOnMount");
|
|
11
|
+
/** Unlike `setTimeout`, rAF doesn't guarantee a positive integer return value, so we can't have
|
|
12
|
+
* a monomorphic `uint` type with `0` meaning empty.
|
|
13
|
+
* See warning note at:
|
|
14
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value */
|
|
15
|
+
const EMPTY = null;
|
|
16
|
+
let LAST_RAF = globalThis.requestAnimationFrame;
|
|
17
|
+
class Scheduler {
|
|
18
|
+
/* This implementation uses an array as a backing data-structure for frame callbacks.
|
|
19
|
+
* It allows `O(1)` callback cancelling by inserting a `null` in the array, though it
|
|
20
|
+
* never calls the native `cancelAnimationFrame` if there are no frames left. This can
|
|
21
|
+
* be much more efficient if there is a call pattern that alterns as
|
|
22
|
+
* "request-cancel-request-cancel-…".
|
|
23
|
+
* But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation
|
|
24
|
+
* frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */
|
|
25
|
+
|
|
26
|
+
callbacks = [];
|
|
27
|
+
callbacksCount = 0;
|
|
28
|
+
nextId = 1;
|
|
29
|
+
startId = 1;
|
|
30
|
+
isScheduled = false;
|
|
31
|
+
tick = timestamp => {
|
|
32
|
+
this.isScheduled = false;
|
|
33
|
+
const currentCallbacks = this.callbacks;
|
|
34
|
+
const currentCallbacksCount = this.callbacksCount;
|
|
35
|
+
|
|
36
|
+
// Update these before iterating, callbacks could call `requestAnimationFrame` again.
|
|
37
|
+
this.callbacks = [];
|
|
38
|
+
this.callbacksCount = 0;
|
|
39
|
+
this.startId = this.nextId;
|
|
40
|
+
if (currentCallbacksCount > 0) {
|
|
41
|
+
for (let i = 0; i < currentCallbacks.length; i += 1) {
|
|
42
|
+
currentCallbacks[i]?.(timestamp);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
request(fn) {
|
|
47
|
+
const id = this.nextId;
|
|
48
|
+
this.nextId += 1;
|
|
49
|
+
this.callbacks.push(fn);
|
|
50
|
+
this.callbacksCount += 1;
|
|
51
|
+
|
|
52
|
+
/* In a test environment with fake timers, a fake `requestAnimationFrame` can be called
|
|
53
|
+
* but there's no guarantee that the animation frame will actually run before the fake
|
|
54
|
+
* timers are teared, which leaves `isScheduled` set, but won't run our `tick()`. */
|
|
55
|
+
const didRAFChange = process.env.NODE_ENV !== 'production' && LAST_RAF !== requestAnimationFrame && (LAST_RAF = requestAnimationFrame, true);
|
|
56
|
+
if (!this.isScheduled || didRAFChange) {
|
|
57
|
+
requestAnimationFrame(this.tick);
|
|
58
|
+
this.isScheduled = true;
|
|
59
|
+
}
|
|
60
|
+
return id;
|
|
61
|
+
}
|
|
62
|
+
cancel(id) {
|
|
63
|
+
const index = id - this.startId;
|
|
64
|
+
if (index < 0 || index >= this.callbacks.length) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
this.callbacks[index] = null;
|
|
68
|
+
this.callbacksCount -= 1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const scheduler = new Scheduler();
|
|
72
|
+
class AnimationFrame {
|
|
73
|
+
static create() {
|
|
74
|
+
return new AnimationFrame();
|
|
75
|
+
}
|
|
76
|
+
static request(fn) {
|
|
77
|
+
return scheduler.request(fn);
|
|
78
|
+
}
|
|
79
|
+
static cancel(id) {
|
|
80
|
+
return scheduler.cancel(id);
|
|
81
|
+
}
|
|
82
|
+
currentId = EMPTY;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
86
|
+
*/
|
|
87
|
+
request(fn) {
|
|
88
|
+
this.cancel();
|
|
89
|
+
this.currentId = scheduler.request(() => {
|
|
90
|
+
this.currentId = EMPTY;
|
|
91
|
+
fn();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
cancel = () => {
|
|
95
|
+
if (this.currentId !== EMPTY) {
|
|
96
|
+
scheduler.cancel(this.currentId);
|
|
97
|
+
this.currentId = EMPTY;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
disposeEffect = () => {
|
|
101
|
+
return this.cancel;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* A `requestAnimationFrame` with automatic cleanup and guard.
|
|
107
|
+
*/
|
|
108
|
+
exports.AnimationFrame = AnimationFrame;
|
|
109
|
+
function useAnimationFrame() {
|
|
110
|
+
const timeout = (0, _useRefWithInit.useRefWithInit)(AnimationFrame.create).current;
|
|
111
|
+
(0, _useOnMount.useOnMount)(timeout.disposeEffect);
|
|
112
|
+
return timeout;
|
|
113
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface UseControlledProps<T = unknown> {
|
|
2
|
+
/**
|
|
3
|
+
* Holds the component value when it's controlled.
|
|
4
|
+
*/
|
|
5
|
+
controlled: T | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* The default value when uncontrolled.
|
|
8
|
+
*/
|
|
9
|
+
default: T | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* The component name displayed in warnings.
|
|
12
|
+
*/
|
|
13
|
+
name: string;
|
|
14
|
+
/**
|
|
15
|
+
* The name of the state variable displayed in warnings.
|
|
16
|
+
*/
|
|
17
|
+
state?: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
export declare function useControlled<T = unknown>({
|
|
20
|
+
controlled,
|
|
21
|
+
default: defaultProp,
|
|
22
|
+
name,
|
|
23
|
+
state
|
|
24
|
+
}: UseControlledProps<T>): [T, (newValue: T | ((prevValue: T) => T)) => void];
|
package/useControlled.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
|
|
4
|
+
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler -- process.env never changes, dependency arrays are intentionally ignored
|
|
5
|
+
/* eslint-disable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */
|
|
6
|
+
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
7
|
+
Object.defineProperty(exports, "__esModule", {
|
|
8
|
+
value: true
|
|
9
|
+
});
|
|
10
|
+
exports.useControlled = useControlled;
|
|
11
|
+
var React = _interopRequireWildcard(require("react"));
|
|
12
|
+
function useControlled({
|
|
13
|
+
controlled,
|
|
14
|
+
default: defaultProp,
|
|
15
|
+
name,
|
|
16
|
+
state = 'value'
|
|
17
|
+
}) {
|
|
18
|
+
// isControlled is ignored in the hook dependency lists as it should never change.
|
|
19
|
+
const {
|
|
20
|
+
current: isControlled
|
|
21
|
+
} = React.useRef(controlled !== undefined);
|
|
22
|
+
const [valueState, setValue] = React.useState(defaultProp);
|
|
23
|
+
const value = isControlled ? controlled : valueState;
|
|
24
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
25
|
+
React.useEffect(() => {
|
|
26
|
+
if (isControlled !== (controlled !== undefined)) {
|
|
27
|
+
console.error([`Tale UI: A component is changing the ${isControlled ? '' : 'un'}controlled ${state} state of ${name} to be ${isControlled ? 'un' : ''}controlled.`, 'Elements should not switch from uncontrolled to controlled (or vice versa).', `Decide between using a controlled or uncontrolled ${name} ` + 'element for the lifetime of the component.', "The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.", 'More info: https://fb.me/react-controlled-components'].join('\n'));
|
|
28
|
+
}
|
|
29
|
+
}, [state, name, controlled]);
|
|
30
|
+
const {
|
|
31
|
+
current: defaultValue
|
|
32
|
+
} = React.useRef(defaultProp);
|
|
33
|
+
React.useEffect(() => {
|
|
34
|
+
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is for more details.
|
|
35
|
+
if (!isControlled && JSON.stringify(defaultValue) !== JSON.stringify(defaultProp)) {
|
|
36
|
+
console.error([`Tale UI: A component is changing the default ${state} state of an uncontrolled ${name} after being initialized. ` + `To suppress this warning opt to use a controlled ${name}.`].join('\n'));
|
|
37
|
+
}
|
|
38
|
+
}, [JSON.stringify(defaultProp)]);
|
|
39
|
+
}
|
|
40
|
+
const setValueIfUncontrolled = React.useCallback(newValue => {
|
|
41
|
+
if (!isControlled) {
|
|
42
|
+
setValue(newValue);
|
|
43
|
+
}
|
|
44
|
+
}, []);
|
|
45
|
+
return [value, setValueIfUncontrolled];
|
|
46
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export type InteractionType = 'mouse' | 'touch' | 'pen' | 'keyboard' | '';
|
|
3
|
+
/**
|
|
4
|
+
* Provides a cross-browser way to determine the type of the pointer used to click.
|
|
5
|
+
* Safari and Firefox do not provide the PointerEvent to the click handler (they use MouseEvent) yet.
|
|
6
|
+
* Additionally, this implementation detects if the click was triggered by the keyboard.
|
|
7
|
+
*
|
|
8
|
+
* @param handler The function to be called when the button is clicked. The first parameter is the original event and the second parameter is the pointer type.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useEnhancedClickHandler(handler: (event: React.MouseEvent | React.PointerEvent, interactionType: InteractionType) => void): {
|
|
11
|
+
onClick: (event: React.MouseEvent | React.PointerEvent) => void;
|
|
12
|
+
onPointerDown: (event: React.PointerEvent) => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
|
|
4
|
+
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.useEnhancedClickHandler = useEnhancedClickHandler;
|
|
9
|
+
var React = _interopRequireWildcard(require("react"));
|
|
10
|
+
/**
|
|
11
|
+
* Provides a cross-browser way to determine the type of the pointer used to click.
|
|
12
|
+
* Safari and Firefox do not provide the PointerEvent to the click handler (they use MouseEvent) yet.
|
|
13
|
+
* Additionally, this implementation detects if the click was triggered by the keyboard.
|
|
14
|
+
*
|
|
15
|
+
* @param handler The function to be called when the button is clicked. The first parameter is the original event and the second parameter is the pointer type.
|
|
16
|
+
*/
|
|
17
|
+
function useEnhancedClickHandler(handler) {
|
|
18
|
+
const lastClickInteractionTypeRef = React.useRef('');
|
|
19
|
+
const handlePointerDown = React.useCallback(event => {
|
|
20
|
+
if (event.defaultPrevented) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
lastClickInteractionTypeRef.current = event.pointerType;
|
|
24
|
+
handler(event, event.pointerType);
|
|
25
|
+
}, [handler]);
|
|
26
|
+
const handleClick = React.useCallback(event => {
|
|
27
|
+
// event.detail has the number of clicks performed on the element. 0 means it was triggered by the keyboard.
|
|
28
|
+
if (event.detail === 0) {
|
|
29
|
+
handler(event, 'keyboard');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if ('pointerType' in event) {
|
|
33
|
+
// Chrome and Edge correctly use PointerEvent
|
|
34
|
+
handler(event, event.pointerType);
|
|
35
|
+
} else {
|
|
36
|
+
handler(event, lastClickInteractionTypeRef.current);
|
|
37
|
+
}
|
|
38
|
+
lastClickInteractionTypeRef.current = '';
|
|
39
|
+
}, [handler]);
|
|
40
|
+
return {
|
|
41
|
+
onClick: handleClick,
|
|
42
|
+
onPointerDown: handlePointerDown
|
|
43
|
+
};
|
|
44
|
+
}
|