@applicaster/zapp-react-native-utils 13.0.0-alpha.1212224153 → 13.0.0-alpha.1302680411
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/README.md +0 -10
- package/appUtils/HooksManager/Hook.ts +2 -2
- package/appUtils/HooksManager/types.ts +2 -2
- package/appUtils/contextKeysManager/contextResolver.ts +6 -2
- package/appUtils/contextKeysManager/index.ts +2 -2
- package/appUtils/contextKeysManager/utils/index.ts +2 -1
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +1 -0
- package/appUtils/focusManager/index.ts +11 -3
- package/appUtils/platform/platformUtils.ts +30 -3
- package/appUtils/playerManager/player.ts +2 -2
- package/equalUtils/__tests__/isEqual/combination.test.ts +263 -0
- package/equalUtils/index.ts +49 -30
- package/focusManager/FocusManager.ts +11 -1
- package/focusManager/index.ts +41 -4
- package/idleUtils/__tests__/withTimeout$.test.ts +37 -0
- package/idleUtils/index.ts +1 -1
- package/idleUtils/withTimeout.ts +15 -2
- package/manifestUtils/__tests__/createConfig.test.js +0 -2
- package/navigationUtils/index.ts +3 -3
- package/package.json +4 -6
- package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +1 -1
- package/reactHooks/layout/useDimensions/useDimensions.ts +8 -0
- package/reactHooks/navigation/__mocks__/useNavigation.ts +3 -0
- package/reactHooks/navigation/index.ts +7 -19
- package/reactHooks/navigation/useGetTabBarHeight.ts +1 -3
- package/reactHooks/navigation/useProfilerLogging.ts +15 -0
- package/reactHooks/state/useRefWithInitialValue.ts +14 -0
- package/reactHooks/state/useStateFromSubscribe.ts +23 -0
- package/reactHooks/usePluginConfiguration.ts +1 -1
- package/reactHooks/useSubscriberFor.ts +4 -3
- package/reactUtils/__tests__/__snapshots__/reactUtilsHelpers.test.js.snap +16 -4
- package/reactUtils/__tests__/reactUtils.test.js +1 -19
- package/reactUtils/__tests__/reactUtilsHelpers.test.js +72 -71
- package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +6 -72
- package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -28
- package/reactUtils/createContext/__tests__/__snapshots__/withConsumer.test.js.snap +3 -4
- package/reactUtils/createContext/__tests__/__snapshots__/withProvider.test.js.snap +7 -3
- package/reactUtils/createContext/__tests__/helpers.test.js +107 -121
- package/reactUtils/createContext/__tests__/{index.test.js → index.test.ts} +2 -2
- package/reactUtils/createContext/__tests__/provider.test.js +4 -6
- package/reactUtils/createContext/__tests__/withConsumer.test.js +12 -12
- package/reactUtils/createContext/__tests__/withProvider.test.js +4 -4
- package/reactUtils/createContext/helpers.ts +6 -1
- package/reactUtils/createContext/index.ts +11 -25
- package/reactUtils/index.ts +0 -11
- package/screenState/index.ts +24 -10
- package/testUtils/index.tsx +0 -10
- package/theme/index.ts +1 -1
- package/time/Timer.ts +4 -1
- package/types.ts +1 -0
- package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
- package/reactUtils/createContext/__tests__/index-no-react.test.js +0 -27
- /package/reactUtils/createContext/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
package/README.md
CHANGED
|
@@ -376,16 +376,6 @@ useEffect(() => {
|
|
|
376
376
|
}, []);
|
|
377
377
|
```
|
|
378
378
|
|
|
379
|
-
### testUtils
|
|
380
|
-
|
|
381
|
-
`@applicaster/zapp-react-native-utils/testUtils`
|
|
382
|
-
|
|
383
|
-
- `testIDEquals: (testId: any) => boolean | { width: number, height: number }` - Function to be used in tandem with enzyme findWhere
|
|
384
|
-
|
|
385
|
-
```javascript
|
|
386
|
-
wrapper.findWhere(testIDEquals("text"));
|
|
387
|
-
```
|
|
388
|
-
|
|
389
379
|
### appUtils - contextKeysManager
|
|
390
380
|
|
|
391
381
|
`@applicaster/zapp-react-native-utils/appUtils/contextKeyManager`
|
|
@@ -16,7 +16,7 @@ const BASE_HOOK_PROPERTIES = ["screen_id", "identifier", "weight"];
|
|
|
16
16
|
* @returns {number} index
|
|
17
17
|
*/
|
|
18
18
|
const hookState: (
|
|
19
|
-
arg0: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS]
|
|
19
|
+
arg0: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS]
|
|
20
20
|
) => number = R.indexOf(R.__, R.values(HOOKS_EVENTS));
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -62,7 +62,7 @@ export class Hook implements HookInterface {
|
|
|
62
62
|
* @param {Array<Any>} args variadic arguments to invoke the handler with
|
|
63
63
|
*/
|
|
64
64
|
setStateAndNotify(
|
|
65
|
-
event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
|
|
65
|
+
event: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS],
|
|
66
66
|
...args
|
|
67
67
|
) {
|
|
68
68
|
this.state = hookState(event);
|
|
@@ -103,7 +103,7 @@ export interface Hook<T extends HookModule = HookModule> {
|
|
|
103
103
|
identifier: string;
|
|
104
104
|
configuration: T["configuration"];
|
|
105
105
|
setStateAndNotify(
|
|
106
|
-
event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
|
|
106
|
+
event: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS],
|
|
107
107
|
opts: {
|
|
108
108
|
error?: typeof Error;
|
|
109
109
|
route?: string;
|
|
@@ -112,7 +112,7 @@ export interface Hook<T extends HookModule = HookModule> {
|
|
|
112
112
|
}
|
|
113
113
|
);
|
|
114
114
|
general?: {
|
|
115
|
-
transition_type: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS];
|
|
115
|
+
transition_type: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS];
|
|
116
116
|
allow_screen_plugin_presentation: boolean;
|
|
117
117
|
is_flow_blocker: boolean;
|
|
118
118
|
};
|
|
@@ -42,12 +42,16 @@ export const resolveObjectValues = async (
|
|
|
42
42
|
|
|
43
43
|
const resolvedEntries = await Promise.all(
|
|
44
44
|
entries.map(async ([key, value]) => {
|
|
45
|
-
const regex = /@{([^/]+)\/([^}]*)}/;
|
|
46
|
-
|
|
47
45
|
if (typeof value !== "string") {
|
|
48
46
|
return [key, value];
|
|
49
47
|
}
|
|
50
48
|
|
|
49
|
+
if (!value.startsWith("@")) {
|
|
50
|
+
return [key, value];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const regex = /@{([^/]+)\/([^}]*)}/;
|
|
54
|
+
|
|
51
55
|
const match = (value as string).match(regex);
|
|
52
56
|
|
|
53
57
|
if (match) {
|
|
@@ -16,12 +16,12 @@ import {
|
|
|
16
16
|
|
|
17
17
|
export { StorageLevel };
|
|
18
18
|
|
|
19
|
-
type KeyNameObj = {
|
|
19
|
+
export type KeyNameObj = {
|
|
20
20
|
namespace: string;
|
|
21
21
|
key: string;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
type KeyName = string | KeyNameObj;
|
|
24
|
+
export type KeyName = string | KeyNameObj;
|
|
25
25
|
|
|
26
26
|
type ParsedKeyAndNamespace = {
|
|
27
27
|
namespace?: string;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
import { DEFAULT_NAMESPACE } from "../consts";
|
|
3
|
+
import { KeyName, KeyNameObj } from "../index";
|
|
3
4
|
|
|
4
5
|
const lastDotRegex = /\.([^.]+)$/;
|
|
5
6
|
const splitByLastDot = R.compose(R.init, R.split(lastDotRegex));
|
|
6
7
|
|
|
7
|
-
export function getNamespaceAndKey(namespacedKey) {
|
|
8
|
+
export function getNamespaceAndKey(namespacedKey: KeyName): KeyNameObj {
|
|
8
9
|
if (typeof namespacedKey !== "string") return namespacedKey;
|
|
9
10
|
|
|
10
11
|
const namespacedKeyProps = namespacedKey.includes(".")
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { subscriber } from "../../functionUtils";
|
|
14
14
|
import { coreLogger } from "../../logger";
|
|
15
15
|
import { ACTION } from "./utils/enums";
|
|
16
|
+
|
|
16
17
|
const logger = coreLogger.addSubsystem("focusManager");
|
|
17
18
|
|
|
18
19
|
const isFocusEnabled = (focusableItem): boolean => {
|
|
@@ -325,8 +326,6 @@ export const focusManager = (function () {
|
|
|
325
326
|
},
|
|
326
327
|
});
|
|
327
328
|
|
|
328
|
-
currentFocusNode = focusCandidate;
|
|
329
|
-
|
|
330
329
|
focusableItem && setFocus(focusCandidate.id, null);
|
|
331
330
|
|
|
332
331
|
return { success: true };
|
|
@@ -346,6 +345,14 @@ export const focusManager = (function () {
|
|
|
346
345
|
});
|
|
347
346
|
}
|
|
348
347
|
|
|
348
|
+
function pressIn() {
|
|
349
|
+
const currentFocusable = getCurrentFocus();
|
|
350
|
+
|
|
351
|
+
if (currentFocusable) {
|
|
352
|
+
currentFocusable.pressIn(null);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
349
356
|
/**
|
|
350
357
|
* calls the `press` method on the current focus component
|
|
351
358
|
* @public
|
|
@@ -477,7 +484,7 @@ export const focusManager = (function () {
|
|
|
477
484
|
function isCurrentFocusOnTheTopScreen() {
|
|
478
485
|
const routes = R.pathOr([], ["root", "children"], focusableTree);
|
|
479
486
|
|
|
480
|
-
if (routes.length <= 1) {
|
|
487
|
+
if (currentFocusNode && routes.length <= 1) {
|
|
481
488
|
// there is only one or zero routes
|
|
482
489
|
return true;
|
|
483
490
|
}
|
|
@@ -553,6 +560,7 @@ export const focusManager = (function () {
|
|
|
553
560
|
invokeHandler,
|
|
554
561
|
removeHandler,
|
|
555
562
|
longPress,
|
|
563
|
+
pressIn,
|
|
556
564
|
pressOut,
|
|
557
565
|
enableFocus,
|
|
558
566
|
setInitialFocus,
|
|
@@ -77,13 +77,22 @@ export class ClosedCaptioningManager {
|
|
|
77
77
|
|
|
78
78
|
private constructor() {
|
|
79
79
|
this.initialize();
|
|
80
|
+
|
|
81
|
+
window["vizioDebug"] = {
|
|
82
|
+
setCCEnabled: (isCCEnabled: boolean) => {
|
|
83
|
+
this.ccState$.next(isCCEnabled);
|
|
84
|
+
},
|
|
85
|
+
};
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
static getInstance(): ClosedCaptioningManager {
|
|
83
89
|
if (!ClosedCaptioningManager.ccManagerInstance) {
|
|
90
|
+
log_debug("ClosedCaptioningManager: Creating new instance");
|
|
84
91
|
ClosedCaptioningManager.ccManagerInstance = new ClosedCaptioningManager();
|
|
85
92
|
}
|
|
86
93
|
|
|
94
|
+
log_debug("ClosedCaptioningManager: Returning existing instance");
|
|
95
|
+
|
|
87
96
|
return ClosedCaptioningManager.ccManagerInstance;
|
|
88
97
|
}
|
|
89
98
|
|
|
@@ -92,23 +101,41 @@ export class ClosedCaptioningManager {
|
|
|
92
101
|
PLATFORM_KEYS.deviceClosedCaptioningEnabled
|
|
93
102
|
);
|
|
94
103
|
|
|
95
|
-
log_debug("Initializing closed captioning manager", { existingState });
|
|
96
|
-
|
|
97
104
|
if (existingState !== null) {
|
|
105
|
+
log_debug(
|
|
106
|
+
`ClosedCaptioningManager: Setting initial state to ${existingState}`
|
|
107
|
+
);
|
|
108
|
+
|
|
98
109
|
this.ccState$.next(existingState === "true" || existingState === true);
|
|
110
|
+
} else {
|
|
111
|
+
log_debug("ClosedCaptioningManager: No existing state found");
|
|
99
112
|
}
|
|
100
113
|
|
|
101
114
|
if (hasVizioAPIs()) {
|
|
115
|
+
log_debug("ClosedCaptioningManager: Setting closed captioning handler");
|
|
116
|
+
|
|
102
117
|
window.VIZIO!.setClosedCaptionHandler((isCCEnabled) => {
|
|
103
|
-
log_debug(
|
|
118
|
+
log_debug(
|
|
119
|
+
"ClosedCaptioningManager: There was a change in the CC state",
|
|
120
|
+
{ isCCEnabled }
|
|
121
|
+
);
|
|
104
122
|
|
|
105
123
|
sessionStorage.setItem(
|
|
106
124
|
PLATFORM_KEYS.deviceClosedCaptioningEnabled,
|
|
107
125
|
isCCEnabled
|
|
108
126
|
);
|
|
109
127
|
|
|
128
|
+
log_debug(
|
|
129
|
+
"ClosedCaptioningManager: Saved CC state to session storage",
|
|
130
|
+
{ isCCEnabled }
|
|
131
|
+
);
|
|
132
|
+
|
|
110
133
|
this.ccState$.next(isCCEnabled);
|
|
111
134
|
});
|
|
135
|
+
} else {
|
|
136
|
+
log_debug(
|
|
137
|
+
"ClosedCaptioningManager: Vizio APIs are not available, skipping setup"
|
|
138
|
+
);
|
|
112
139
|
}
|
|
113
140
|
}
|
|
114
141
|
|
|
@@ -154,8 +154,8 @@ export class Player {
|
|
|
154
154
|
this.isSeeking()
|
|
155
155
|
? this.playerState.seekPosition
|
|
156
156
|
: this.playerState.adState
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
? this.playerState.adState.adPosition
|
|
158
|
+
: this.playerState.contentPosition;
|
|
159
159
|
|
|
160
160
|
getEntry = (): ZappEntry | null => this.entry;
|
|
161
161
|
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { isEqual } from "../..";
|
|
2
|
+
|
|
3
|
+
const array = [1, 2, 3];
|
|
4
|
+
const sameProp = "sameProp";
|
|
5
|
+
|
|
6
|
+
describe("isEqual - comprehensive tests", () => {
|
|
7
|
+
describe("all conditions together", () => {
|
|
8
|
+
it("all conditions checked and not equal", () => {
|
|
9
|
+
const prev = {
|
|
10
|
+
byValueProp: { a: 1, b: 2 },
|
|
11
|
+
byRefProp: array,
|
|
12
|
+
byComparatorProp: "test",
|
|
13
|
+
extraProp1: 123,
|
|
14
|
+
extraProp2: sameProp,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const next = {
|
|
18
|
+
byValueProp: { a: 1, b: 2 },
|
|
19
|
+
byRefProp: array,
|
|
20
|
+
byComparatorProp: "different",
|
|
21
|
+
extraProp1: 456,
|
|
22
|
+
extraProp2: sameProp,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const customComparator = jest.fn().mockReturnValue(true);
|
|
26
|
+
|
|
27
|
+
const result = isEqual({
|
|
28
|
+
byValue: ["byValueProp"],
|
|
29
|
+
byReference: ["byRefProp"],
|
|
30
|
+
byComparator: {
|
|
31
|
+
comparator: customComparator,
|
|
32
|
+
keys: ["byComparatorProp"],
|
|
33
|
+
},
|
|
34
|
+
compareRemainingKeysBySameValue: true,
|
|
35
|
+
})(prev, next);
|
|
36
|
+
|
|
37
|
+
expect(result).toBe(false);
|
|
38
|
+
|
|
39
|
+
expect(customComparator).toHaveBeenCalledWith(
|
|
40
|
+
prev.byComparatorProp,
|
|
41
|
+
next.byComparatorProp
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("all conditions pass with exact remaining keys check", () => {
|
|
46
|
+
const prev = {
|
|
47
|
+
byValueProp: { a: 1, b: 2 },
|
|
48
|
+
byRefProp: array,
|
|
49
|
+
byComparatorProp: "test",
|
|
50
|
+
extraProp: sameProp,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const next = {
|
|
54
|
+
byValueProp: { a: 1, b: 2 },
|
|
55
|
+
byRefProp: array,
|
|
56
|
+
byComparatorProp: "test",
|
|
57
|
+
extraProp: sameProp,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const customComparator = jest.fn().mockReturnValue(true);
|
|
61
|
+
|
|
62
|
+
const result = isEqual({
|
|
63
|
+
byValue: ["byValueProp"],
|
|
64
|
+
byReference: ["byRefProp"],
|
|
65
|
+
byComparator: {
|
|
66
|
+
comparator: customComparator,
|
|
67
|
+
keys: ["byComparatorProp"],
|
|
68
|
+
},
|
|
69
|
+
compareRemainingKeysBySameValue: true,
|
|
70
|
+
})(prev, next);
|
|
71
|
+
|
|
72
|
+
expect(result).toBe(true);
|
|
73
|
+
|
|
74
|
+
expect(customComparator).toHaveBeenCalledWith(
|
|
75
|
+
prev.byComparatorProp,
|
|
76
|
+
next.byComparatorProp
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("byReference check fails first (early return)", () => {
|
|
81
|
+
const prev = {
|
|
82
|
+
byValueProp: { a: 1, b: 2 },
|
|
83
|
+
byRefProp: array,
|
|
84
|
+
byComparatorProp: sameProp,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const next = {
|
|
88
|
+
byValueProp: { a: 1, b: 2 },
|
|
89
|
+
byRefProp: [1, 2, 3],
|
|
90
|
+
byComparatorProp: sameProp,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const customComparator = jest.fn().mockReturnValue(true);
|
|
94
|
+
|
|
95
|
+
const result = isEqual({
|
|
96
|
+
byValue: ["byValueProp"],
|
|
97
|
+
byReference: ["byRefProp"],
|
|
98
|
+
byComparator: {
|
|
99
|
+
comparator: customComparator,
|
|
100
|
+
keys: ["byComparatorProp"],
|
|
101
|
+
},
|
|
102
|
+
})(prev, next);
|
|
103
|
+
|
|
104
|
+
expect(result).toBe(false);
|
|
105
|
+
expect(customComparator).not.toHaveBeenCalled();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("byValue check fails after byReference passes", () => {
|
|
109
|
+
const prev = {
|
|
110
|
+
byValueProp: { a: 1, b: 2 },
|
|
111
|
+
byRefProp: array,
|
|
112
|
+
byComparatorProp: sameProp,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const next = {
|
|
116
|
+
byValueProp: { a: 1, b: 3 },
|
|
117
|
+
byRefProp: array,
|
|
118
|
+
byComparatorProp: sameProp,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const customComparator = jest.fn().mockReturnValue(true);
|
|
122
|
+
|
|
123
|
+
const result = isEqual({
|
|
124
|
+
byValue: ["byValueProp"],
|
|
125
|
+
byReference: ["byRefProp"],
|
|
126
|
+
byComparator: {
|
|
127
|
+
comparator: customComparator,
|
|
128
|
+
keys: ["byComparatorProp"],
|
|
129
|
+
},
|
|
130
|
+
})(prev, next);
|
|
131
|
+
|
|
132
|
+
expect(result).toBe(false);
|
|
133
|
+
expect(customComparator).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("byComparator check fails after other checks pass", () => {
|
|
137
|
+
const prev = {
|
|
138
|
+
byValueProp: { a: 1, b: 2 },
|
|
139
|
+
byRefProp: array,
|
|
140
|
+
byComparatorProp: "test",
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const next = {
|
|
144
|
+
byValueProp: { a: 1, b: 2 },
|
|
145
|
+
byRefProp: array,
|
|
146
|
+
byComparatorProp: "different",
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const customComparator = jest.fn().mockReturnValue(false);
|
|
150
|
+
|
|
151
|
+
const result = isEqual({
|
|
152
|
+
byValue: ["byValueProp"],
|
|
153
|
+
byReference: ["byRefProp"],
|
|
154
|
+
byComparator: {
|
|
155
|
+
comparator: customComparator,
|
|
156
|
+
keys: ["byComparatorProp"],
|
|
157
|
+
},
|
|
158
|
+
})(prev, next);
|
|
159
|
+
|
|
160
|
+
expect(result).toBe(false);
|
|
161
|
+
|
|
162
|
+
expect(customComparator).toHaveBeenCalledWith(
|
|
163
|
+
prev.byComparatorProp,
|
|
164
|
+
next.byComparatorProp
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("remaining keys comparison fails", () => {
|
|
169
|
+
const sharedArray = [1, 2, 3];
|
|
170
|
+
|
|
171
|
+
const prev = {
|
|
172
|
+
byValueProp: { a: 1, b: 2 },
|
|
173
|
+
byRefProp: sharedArray,
|
|
174
|
+
byComparatorProp: "test",
|
|
175
|
+
extraProp: "original",
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const next = {
|
|
179
|
+
byValueProp: { a: 1, b: 2 },
|
|
180
|
+
byRefProp: sharedArray,
|
|
181
|
+
byComparatorProp: "different",
|
|
182
|
+
extraProp: "changed",
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const customComparator = jest.fn().mockReturnValue(true);
|
|
186
|
+
|
|
187
|
+
const result = isEqual({
|
|
188
|
+
byValue: ["byValueProp"],
|
|
189
|
+
byReference: ["byRefProp"],
|
|
190
|
+
byComparator: {
|
|
191
|
+
comparator: customComparator,
|
|
192
|
+
keys: ["byComparatorProp"],
|
|
193
|
+
},
|
|
194
|
+
compareRemainingKeysBySameValue: true,
|
|
195
|
+
})(prev, next);
|
|
196
|
+
|
|
197
|
+
expect(result).toBe(false);
|
|
198
|
+
expect(customComparator).toHaveBeenCalled();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("with debug flag", () => {
|
|
202
|
+
const consoleSpy = jest.spyOn(console, "log").mockImplementation();
|
|
203
|
+
|
|
204
|
+
const prev = {
|
|
205
|
+
byValueProp: { a: 1, b: 2 },
|
|
206
|
+
byRefProp: array,
|
|
207
|
+
byComparatorProp: "test",
|
|
208
|
+
extraProp: sameProp,
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const next = {
|
|
212
|
+
byValueProp: { a: 1, b: 2 },
|
|
213
|
+
byRefProp: array,
|
|
214
|
+
byComparatorProp: "different",
|
|
215
|
+
extraProp: sameProp,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const customComparator = jest.fn().mockReturnValue(true);
|
|
219
|
+
|
|
220
|
+
const result = isEqual({
|
|
221
|
+
byValue: ["byValueProp"],
|
|
222
|
+
byReference: ["byRefProp"],
|
|
223
|
+
byComparator: {
|
|
224
|
+
comparator: customComparator,
|
|
225
|
+
keys: ["byComparatorProp"],
|
|
226
|
+
},
|
|
227
|
+
compareRemainingKeysBySameValue: true,
|
|
228
|
+
debug: true,
|
|
229
|
+
})(prev, next);
|
|
230
|
+
|
|
231
|
+
expect(result).toBe(true);
|
|
232
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
233
|
+
|
|
234
|
+
consoleSpy.mockRestore();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("handles missing properties", () => {
|
|
238
|
+
const prev = {
|
|
239
|
+
byValueProp: { a: 1, b: 2 },
|
|
240
|
+
byRefProp: [1, 2, 3],
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const next = {
|
|
244
|
+
byValueProp: { a: 1, b: 2 },
|
|
245
|
+
byComparatorProp: "test",
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const customComparator = jest.fn().mockReturnValue(true);
|
|
249
|
+
|
|
250
|
+
const result = isEqual({
|
|
251
|
+
byValue: ["byValueProp"],
|
|
252
|
+
byReference: ["byRefProp"],
|
|
253
|
+
byComparator: {
|
|
254
|
+
comparator: customComparator,
|
|
255
|
+
keys: ["byComparatorProp"],
|
|
256
|
+
},
|
|
257
|
+
})(prev, next);
|
|
258
|
+
|
|
259
|
+
expect(result).toBe(false);
|
|
260
|
+
expect(customComparator).not.toHaveBeenCalled();
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
});
|
package/equalUtils/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* eslint no-console: off */
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { equals } from "ramda";
|
|
4
|
+
|
|
5
|
+
const alwaysTrue = () => true;
|
|
4
6
|
|
|
5
7
|
export const isParentFocusEqual = (
|
|
6
8
|
prevParentFocus: ParentFocus,
|
|
@@ -18,7 +20,7 @@ export const isEqual =
|
|
|
18
20
|
({
|
|
19
21
|
byValue = [],
|
|
20
22
|
byReference = [],
|
|
21
|
-
byComparator = { comparator:
|
|
23
|
+
byComparator = { comparator: alwaysTrue, keys: [] },
|
|
22
24
|
debug = false,
|
|
23
25
|
compareRemainingKeysBySameValue = false,
|
|
24
26
|
}: {
|
|
@@ -29,42 +31,59 @@ export const isEqual =
|
|
|
29
31
|
compareRemainingKeysBySameValue?: boolean;
|
|
30
32
|
}) =>
|
|
31
33
|
(prev, next) => {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
for (const key of byReference) {
|
|
35
|
+
if (prev[key] !== next[key]) {
|
|
36
|
+
if (debug) console.log({ isEqualByReference: false });
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
39
41
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
(key) => byComparator.comparator(prev[key], next[key]),
|
|
44
|
-
byComparator.keys
|
|
45
|
-
);
|
|
42
|
+
for (const key of byValue) {
|
|
43
|
+
if (!equals(prev[key], next[key])) {
|
|
44
|
+
if (debug) console.log({ isEqualByValue: false });
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for (const key of byComparator.keys) {
|
|
51
|
+
if (!byComparator.comparator(prev[key], next[key])) {
|
|
52
|
+
if (debug) console.log({ isEqualByComparator: false });
|
|
53
|
+
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
49
56
|
}
|
|
50
57
|
|
|
51
58
|
if (compareRemainingKeysBySameValue) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
const allKeys = new Set([...Object.keys(prev), ...Object.keys(next)]);
|
|
60
|
+
|
|
61
|
+
const declaredKeys = new Set([
|
|
62
|
+
...byValue,
|
|
63
|
+
...byReference,
|
|
64
|
+
...byComparator.keys,
|
|
65
|
+
]);
|
|
56
66
|
|
|
57
|
-
const
|
|
58
|
-
Object.is(prev[key], next[key])
|
|
59
|
-
|
|
67
|
+
for (const key of Array.from(allKeys)) {
|
|
68
|
+
if (!declaredKeys.has(key) && !Object.is(prev[key], next[key])) {
|
|
69
|
+
if (debug) console.log({ isRestKeysEqualAllBySameValue: false });
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// if we made it here, everything matched
|
|
77
|
+
if (debug) {
|
|
78
|
+
console.log({
|
|
79
|
+
isEqualByValue: true,
|
|
80
|
+
isEqualByReference: true,
|
|
81
|
+
isEqualByComparator: true,
|
|
82
|
+
isRestKeysEqualAllBySameValue: compareRemainingKeysBySameValue
|
|
83
|
+
? true
|
|
84
|
+
: undefined,
|
|
85
|
+
});
|
|
67
86
|
}
|
|
68
87
|
|
|
69
|
-
return
|
|
88
|
+
return true;
|
|
70
89
|
};
|
|
@@ -250,7 +250,17 @@ class FocusManager {
|
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
onDisableFocusChange = (id) => {
|
|
253
|
-
|
|
253
|
+
const isFocused = FocusManager.instance.isFocused(id);
|
|
254
|
+
|
|
255
|
+
const isDescendantFocused = (() => {
|
|
256
|
+
try {
|
|
257
|
+
return FocusManager.instance.isAnyDescendantFocused(id);
|
|
258
|
+
} catch (_e) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
})();
|
|
262
|
+
|
|
263
|
+
if (isFocused || isDescendantFocused) {
|
|
254
264
|
// Move focus to next one
|
|
255
265
|
const nextFocus = FocusManager.instance.focused?.props
|
|
256
266
|
?.nextFocusDown as string;
|