@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.
Files changed (165) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +3 -0
  4. package/detectBrowser.d.ts +8 -0
  5. package/detectBrowser.js +64 -0
  6. package/empty.d.ts +3 -0
  7. package/empty.js +10 -0
  8. package/error.d.ts +2 -0
  9. package/error.js +23 -0
  10. package/esm/detectBrowser.d.ts +8 -0
  11. package/esm/detectBrowser.js +58 -0
  12. package/esm/empty.d.ts +3 -0
  13. package/esm/empty.js +3 -0
  14. package/esm/error.d.ts +2 -0
  15. package/esm/error.js +16 -0
  16. package/esm/fastHooks.d.ts +14 -0
  17. package/esm/fastHooks.js +43 -0
  18. package/esm/fastObjectShallowCompare.d.ts +1 -0
  19. package/esm/fastObjectShallowCompare.js +29 -0
  20. package/esm/formatErrorMessage.d.ts +18 -0
  21. package/esm/formatErrorMessage.js +26 -0
  22. package/esm/generateId.d.ts +1 -0
  23. package/esm/generateId.js +5 -0
  24. package/esm/getReactElementRef.d.ts +5 -0
  25. package/esm/getReactElementRef.js +14 -0
  26. package/esm/inertValue.d.ts +1 -0
  27. package/esm/inertValue.js +8 -0
  28. package/esm/isElementDisabled.d.ts +1 -0
  29. package/esm/isElementDisabled.js +3 -0
  30. package/esm/isMouseWithinBounds.d.ts +1 -0
  31. package/esm/isMouseWithinBounds.js +10 -0
  32. package/esm/mergeObjects.d.ts +1 -0
  33. package/esm/mergeObjects.js +15 -0
  34. package/esm/owner.d.ts +2 -0
  35. package/esm/owner.js +4 -0
  36. package/esm/package.json +1 -0
  37. package/esm/reactVersion.d.ts +3 -0
  38. package/esm/reactVersion.js +5 -0
  39. package/esm/safeReact.d.ts +2 -0
  40. package/esm/safeReact.js +6 -0
  41. package/esm/store/ReactStore.d.ts +91 -0
  42. package/esm/store/ReactStore.js +199 -0
  43. package/esm/store/Store.d.ts +58 -0
  44. package/esm/store/Store.js +111 -0
  45. package/esm/store/StoreInspector.d.ts +41 -0
  46. package/esm/store/StoreInspector.js +537 -0
  47. package/esm/store/createSelector.d.ts +30 -0
  48. package/esm/store/createSelector.js +148 -0
  49. package/esm/store/index.d.ts +5 -0
  50. package/esm/store/index.js +5 -0
  51. package/esm/store/useStore.d.ts +22 -0
  52. package/esm/store/useStore.js +107 -0
  53. package/esm/testUtils.d.ts +17 -0
  54. package/esm/testUtils.js +19 -0
  55. package/esm/useAnimationFrame.d.ts +18 -0
  56. package/esm/useAnimationFrame.js +106 -0
  57. package/esm/useControlled.d.ts +24 -0
  58. package/esm/useControlled.js +40 -0
  59. package/esm/useEnhancedClickHandler.d.ts +13 -0
  60. package/esm/useEnhancedClickHandler.js +38 -0
  61. package/esm/useForcedRerendering.d.ts +4 -0
  62. package/esm/useForcedRerendering.js +13 -0
  63. package/esm/useId.d.ts +7 -0
  64. package/esm/useId.js +41 -0
  65. package/esm/useInterval.d.ts +13 -0
  66. package/esm/useInterval.js +36 -0
  67. package/esm/useIsoLayoutEffect.d.ts +2 -0
  68. package/esm/useIsoLayoutEffect.js +5 -0
  69. package/esm/useMergedRefs.d.ts +21 -0
  70. package/esm/useMergedRefs.js +108 -0
  71. package/esm/useOnFirstRender.d.ts +1 -0
  72. package/esm/useOnFirstRender.js +10 -0
  73. package/esm/useOnMount.d.ts +5 -0
  74. package/esm/useOnMount.js +14 -0
  75. package/esm/usePreviousValue.d.ts +6 -0
  76. package/esm/usePreviousValue.js +22 -0
  77. package/esm/useRefWithInit.d.ts +10 -0
  78. package/esm/useRefWithInit.js +20 -0
  79. package/esm/useScrollLock.d.ts +7 -0
  80. package/esm/useScrollLock.js +244 -0
  81. package/esm/useStableCallback.d.ts +13 -0
  82. package/esm/useStableCallback.js +44 -0
  83. package/esm/useTimeout.d.ts +17 -0
  84. package/esm/useTimeout.js +43 -0
  85. package/esm/useValueAsRef.d.ts +10 -0
  86. package/esm/useValueAsRef.js +28 -0
  87. package/esm/visuallyHidden.d.ts +3 -0
  88. package/esm/visuallyHidden.js +20 -0
  89. package/esm/warn.d.ts +1 -0
  90. package/esm/warn.js +13 -0
  91. package/fastHooks.d.ts +14 -0
  92. package/fastHooks.js +54 -0
  93. package/fastObjectShallowCompare.d.ts +1 -0
  94. package/fastObjectShallowCompare.js +35 -0
  95. package/formatErrorMessage.d.ts +18 -0
  96. package/formatErrorMessage.js +33 -0
  97. package/generateId.d.ts +1 -0
  98. package/generateId.js +11 -0
  99. package/getReactElementRef.d.ts +5 -0
  100. package/getReactElementRef.js +20 -0
  101. package/inertValue.d.ts +1 -0
  102. package/inertValue.js +14 -0
  103. package/isElementDisabled.d.ts +1 -0
  104. package/isElementDisabled.js +9 -0
  105. package/isMouseWithinBounds.d.ts +1 -0
  106. package/isMouseWithinBounds.js +16 -0
  107. package/mergeObjects.d.ts +1 -0
  108. package/mergeObjects.js +21 -0
  109. package/owner.d.ts +2 -0
  110. package/owner.js +16 -0
  111. package/package.json +64 -0
  112. package/reactVersion.d.ts +3 -0
  113. package/reactVersion.js +12 -0
  114. package/safeReact.d.ts +2 -0
  115. package/safeReact.js +12 -0
  116. package/store/ReactStore.d.ts +91 -0
  117. package/store/ReactStore.js +205 -0
  118. package/store/Store.d.ts +58 -0
  119. package/store/Store.js +118 -0
  120. package/store/StoreInspector.d.ts +41 -0
  121. package/store/StoreInspector.js +544 -0
  122. package/store/createSelector.d.ts +30 -0
  123. package/store/createSelector.js +154 -0
  124. package/store/index.d.ts +5 -0
  125. package/store/index.js +60 -0
  126. package/store/useStore.d.ts +22 -0
  127. package/store/useStore.js +115 -0
  128. package/testUtils.d.ts +17 -0
  129. package/testUtils.js +26 -0
  130. package/useAnimationFrame.d.ts +18 -0
  131. package/useAnimationFrame.js +113 -0
  132. package/useControlled.d.ts +24 -0
  133. package/useControlled.js +46 -0
  134. package/useEnhancedClickHandler.d.ts +13 -0
  135. package/useEnhancedClickHandler.js +44 -0
  136. package/useForcedRerendering.d.ts +4 -0
  137. package/useForcedRerendering.js +18 -0
  138. package/useId.d.ts +7 -0
  139. package/useId.js +47 -0
  140. package/useInterval.d.ts +13 -0
  141. package/useInterval.js +43 -0
  142. package/useIsoLayoutEffect.d.ts +2 -0
  143. package/useIsoLayoutEffect.js +11 -0
  144. package/useMergedRefs.d.ts +21 -0
  145. package/useMergedRefs.js +114 -0
  146. package/useOnFirstRender.d.ts +1 -0
  147. package/useOnFirstRender.js +16 -0
  148. package/useOnMount.d.ts +5 -0
  149. package/useOnMount.js +20 -0
  150. package/usePreviousValue.d.ts +6 -0
  151. package/usePreviousValue.js +27 -0
  152. package/useRefWithInit.d.ts +10 -0
  153. package/useRefWithInit.js +26 -0
  154. package/useScrollLock.d.ts +7 -0
  155. package/useScrollLock.js +249 -0
  156. package/useStableCallback.d.ts +13 -0
  157. package/useStableCallback.js +49 -0
  158. package/useTimeout.d.ts +17 -0
  159. package/useTimeout.js +50 -0
  160. package/useValueAsRef.d.ts +10 -0
  161. package/useValueAsRef.js +32 -0
  162. package/visuallyHidden.d.ts +3 -0
  163. package/visuallyHidden.js +26 -0
  164. package/warn.d.ts +1 -0
  165. 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;
@@ -0,0 +1,5 @@
1
+ export * from "./createSelector.js";
2
+ export * from "./useStore.js";
3
+ export * from "./Store.js";
4
+ export * from "./ReactStore.js";
5
+ export * from "./StoreInspector.js";
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];
@@ -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
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Returns a function that forces a rerender.
3
+ */
4
+ export declare function useForcedRerendering(): () => void;