@applicaster/zapp-react-native-utils 16.0.0-rc.12 → 16.0.0-rc.121
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/actionUtils/index.ts +3 -1
- package/actionsExecutor/ActionExecutor.ts +57 -12
- package/actionsExecutor/ActionExecutorContext.tsx +113 -314
- package/actionsExecutor/__tests__/ActionExecutor.test.ts +71 -0
- package/actionsExecutor/__tests__/feedDecorator.test.ts +61 -0
- package/actionsExecutor/actions/__tests__/dismissBottomSheet.test.ts +25 -0
- package/actionsExecutor/actions/__tests__/goBack.test.ts +62 -0
- package/actionsExecutor/actions/__tests__/goHome.test.ts +19 -0
- package/actionsExecutor/actions/__tests__/loadItemsFromSource.test.ts +88 -0
- package/actionsExecutor/actions/__tests__/navigateToScreen.test.ts +267 -0
- package/actionsExecutor/actions/__tests__/openBottomSheet.customContent.test.ts +100 -0
- package/actionsExecutor/actions/__tests__/openBottomSheet.inlineItems.test.ts +300 -0
- package/actionsExecutor/actions/__tests__/presentScreen.test.ts +127 -0
- package/actionsExecutor/actions/__tests__/showAlert.test.ts +49 -0
- package/actionsExecutor/actions/__tests__/showToast.test.ts +88 -0
- package/actionsExecutor/actions/appRestart.ts +24 -0
- package/actionsExecutor/actions/confirmDialog.ts +53 -0
- package/actionsExecutor/actions/dismissBottomSheet.ts +23 -0
- package/actionsExecutor/actions/goBack.ts +60 -0
- package/actionsExecutor/actions/goHome.ts +31 -0
- package/actionsExecutor/actions/index.ts +42 -0
- package/actionsExecutor/actions/localStorageRemove.ts +27 -0
- package/actionsExecutor/actions/localStorageSet.ts +28 -0
- package/actionsExecutor/actions/localStorageToggleFlag.ts +28 -0
- package/actionsExecutor/actions/navigateToScreen.ts +121 -0
- package/actionsExecutor/actions/openBottomSheet.ts +339 -0
- package/actionsExecutor/actions/presentScreen.ts +78 -0
- package/actionsExecutor/actions/refreshComponent.ts +85 -0
- package/actionsExecutor/actions/screenSetVariable.ts +35 -0
- package/actionsExecutor/actions/screenToggleFlag.ts +38 -0
- package/actionsExecutor/actions/sendCloudEvent.ts +93 -0
- package/actionsExecutor/actions/sessionStorageRemove.ts +19 -0
- package/actionsExecutor/actions/sessionStorageSet.ts +20 -0
- package/actionsExecutor/actions/sessionStorageToggleFlag.ts +15 -0
- package/actionsExecutor/actions/showAlert.ts +51 -0
- package/actionsExecutor/actions/showToast.ts +87 -0
- package/actionsExecutor/actions/switchLayout.ts +40 -0
- package/actionsExecutor/consts.ts +27 -0
- package/actionsExecutor/feedDecorator.ts +6 -6
- package/actionsExecutor/types.ts +59 -0
- package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +2 -2
- package/analyticsUtils/PlayerAnalyticsManager.ts +12 -2
- package/analyticsUtils/__tests__/analyticsMapper.test.ts +35 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testACP_events.json +1 -1
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testBlockUnlistedParams_rules.json +1 -1
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_events.json +4 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_rules.json +6 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEventRegex_events.json +3 -9
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_events.json +18 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_rules.json +16 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_events.json +4 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_rules.json +6 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_events.json +4 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_rules.json +6 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_events.json +4 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_rules.json +6 -0
- package/analyticsUtils/__tests__/fixtures/index.js +20 -0
- package/analyticsUtils/analyticsMapper.ts +4 -1
- package/analyticsUtils/playerAnalyticsTracker.ts +26 -3
- package/appUtils/HooksManager/index.ts +9 -0
- package/appUtils/contextKeysManager/__tests__/getKey/failure.test.ts +1 -1
- package/appUtils/contextKeysManager/__tests__/removeKey/failure.test.ts +1 -1
- package/appUtils/contextKeysManager/__tests__/setKey/failure/invalidKey.test.ts +4 -4
- package/appUtils/contextKeysManager/index.ts +1 -1
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +142 -59
- package/appUtils/playerManager/OverlayObserver/__tests__/getUpcomingQueue.test.ts +67 -0
- package/appUtils/playerManager/OverlayObserver/__tests__/liveContent.test.ts +205 -0
- package/appUtils/playerManager/OverlayObserver/__tests__/utils.test.ts +56 -0
- package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.android.tv.ts +4 -0
- package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.ios.tv.ts +4 -0
- package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.ts +24 -0
- package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.web.ts +4 -0
- package/appUtils/playerManager/OverlayObserver/utils.ts +51 -20
- package/appUtils/playerManager/__tests__/playerContent.test.ts +403 -0
- package/appUtils/playerManager/__tests__/playerFactory.test.ts +1 -1
- package/appUtils/playerManager/__tests__/playerNative.test.ts +114 -0
- package/appUtils/playerManager/__tests__/playerNativeCommand.test.ts +62 -0
- package/appUtils/playerManager/__tests__/playerToolbox.test.ts +97 -0
- package/appUtils/playerManager/__tests__/usePlayerContent.test.tsx +64 -0
- package/appUtils/playerManager/__tests__/usePlayerControllerSetup.test.tsx +62 -0
- package/appUtils/playerManager/{conts.ts → const.ts} +33 -0
- package/appUtils/playerManager/index.ts +8 -1
- package/appUtils/playerManager/player.ts +125 -3
- package/appUtils/playerManager/playerFactory.ts +1 -1
- package/appUtils/playerManager/playerNative.ts +28 -4
- package/appUtils/playerManager/playerNativeCommand.ts +3 -6
- package/appUtils/playerManager/playerToolbox.ts +157 -0
- package/appUtils/playerManager/usePlayerContent.tsx +43 -0
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +7 -1
- package/appUtils/playerManager/userLanguagePreference.ts +1 -1
- package/arrayUtils/__tests__/{anyThruthy.test.ts → anyTruthy.test.ts} +8 -0
- package/arrayUtils/__tests__/arrayUtils.test.ts +165 -108
- package/arrayUtils/__tests__/isEmptyArray.test.ts +11 -0
- package/arrayUtils/__tests__/isFilledArray.test.ts +12 -0
- package/arrayUtils/__tests__/isFirst.test.ts +17 -0
- package/arrayUtils/__tests__/isIndexInRange.test.ts +14 -0
- package/arrayUtils/__tests__/isLast.test.ts +31 -0
- package/arrayUtils/__tests__/makeListOf.test.ts +31 -0
- package/arrayUtils/__tests__/makeListOfIndexes.test.ts +20 -0
- package/arrayUtils/__tests__/reorderByIds.test.ts +63 -0
- package/arrayUtils/__tests__/sample.test.ts +61 -0
- package/arrayUtils/index.ts +119 -20
- package/bottomSheet/__tests__/scrollContext.test.tsx +35 -0
- package/bottomSheet/index.ts +17 -0
- package/cellUtils/__tests__/getButtonsEnabled.test.ts +28 -0
- package/cellUtils/__tests__/getCellNavigationEnabled.test.ts +36 -0
- package/cellUtils/__tests__/getIsCellNavigationEnabled.test.ts +35 -0
- package/cellUtils/__tests__/isCellNavigationEnabled.test.ts +21 -0
- package/cellUtils/index.ts +73 -8
- package/colorUtils/__tests__/isTransparentColor.test.ts +76 -0
- package/colorUtils/__tests__/isValidColor.test.ts +70 -0
- package/colorUtils/index.ts +50 -0
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +21 -0
- package/configurationUtils/__tests__/modalBlocksParser.test.ts +392 -0
- package/configurationUtils/manifestKeyParser.ts +50 -10
- package/configurationUtils/modalBlocksParser.ts +252 -0
- package/entryActions/__tests__/buildEntryActions.test.ts +235 -0
- package/entryActions/aliasPresentation.ts +108 -0
- package/entryActions/buildEntryActions.ts +167 -0
- package/entryActions/index.ts +15 -0
- package/entryActions/types.ts +39 -0
- package/focusManager/FocusManager.ts +26 -0
- package/focusManager/__tests__/FocusManager.test.ts +9 -0
- package/localizationUtils/index.ts +12 -6
- package/logger/__tests__/xrayToolbox.test.ts +69 -0
- package/logger/xrayToolbox.ts +67 -0
- package/manifestUtils/__tests__/player.audioControls.test.js +158 -0
- package/manifestUtils/_internals/index.js +14 -3
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +41 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +357 -20
- package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +84 -0
- package/manifestUtils/fieldUtils/index.js +125 -0
- package/manifestUtils/index.js +3 -0
- package/manifestUtils/keys.js +15 -1
- package/manifestUtils/mobileAction/button/index.js +16 -0
- package/manifestUtils/mobileAction/container/__tests__/mobileActionButtonsContainer.test.js +21 -0
- package/manifestUtils/mobileAction/container/index.js +3 -1
- package/manifestUtils/mobileAction/groups/__tests__/buildMobileActionButtonGroups.test.js +1 -1
- package/manifestUtils/mobileAction/groups/defaults.js +5 -2
- package/manifestUtils/modalBlocks.js +304 -0
- package/manifestUtils/platformIsTV.js +1 -0
- package/modalState/ContentViewModel.ts +113 -0
- package/modalState/EditableCollection.ts +17 -0
- package/modalState/EditableCollectionRegistry.ts +51 -0
- package/modalState/ModalOrchestrator.ts +212 -0
- package/modalState/RemoteEditableCollection.ts +235 -0
- package/modalState/__tests__/ContentViewModel.editable.test.ts +69 -0
- package/modalState/__tests__/ContentViewModel.test.ts +165 -0
- package/modalState/__tests__/EditableCollectionRegistry.test.ts +112 -0
- package/modalState/__tests__/ModalOrchestrator.phase3.test.ts +63 -0
- package/modalState/__tests__/RemoteEditableCollection.test.ts +415 -0
- package/modalState/__tests__/index.test.ts +30 -1
- package/modalState/__tests__/useBottomSheetContent.test.ts +349 -0
- package/modalState/__tests__/useModalStoreState.test.ts +142 -0
- package/modalState/index.ts +35 -83
- package/modalState/store.ts +109 -0
- package/modalState/types.ts +162 -0
- package/modalState/useBottomSheetContent.ts +109 -0
- package/navigationUtils/xrayNavigator.ts +12 -0
- package/numberUtils/__tests__/isMinusZero.test.ts +20 -0
- package/numberUtils/__tests__/isZero.test.ts +27 -0
- package/numberUtils/__tests__/requireNumber.test.ts +50 -0
- package/numberUtils/__tests__/toNumber.test.ts +27 -0
- package/numberUtils/__tests__/toNumberWithDefault.test.ts +64 -0
- package/numberUtils/__tests__/toNumberWithDefaultZero.test.ts +48 -0
- package/numberUtils/index.ts +27 -8
- package/package.json +2 -2
- package/pipesUtils/__tests__/buildUrlWithQuery.test.ts +33 -0
- package/pipesUtils/__tests__/withPipesEndpoint.test.tsx +56 -0
- package/pipesUtils/index.ts +1 -0
- package/pipesUtils/withPipesEndpoint.tsx +54 -0
- package/playerUtils/__tests__/contentDataKeys.test.ts +297 -0
- package/playerUtils/__tests__/resolvePlayerActions.test.ts +138 -0
- package/playerUtils/__tests__/resolvePlayerTitleSubtitle.test.ts +180 -0
- package/playerUtils/contentDataKeys.ts +134 -0
- package/playerUtils/index.ts +37 -16
- package/playerUtils/isAudioItem.ts +26 -0
- package/playerUtils/resolvePlayerActions.ts +71 -0
- package/playerUtils/resolvePlayerTitleSubtitle.ts +76 -0
- package/pluginUtils/__tests__/pluginUtils.test.js +32 -0
- package/pluginUtils/index.ts +29 -0
- package/reactHooks/__tests__/getPluginConfiguration.test.ts +82 -0
- package/reactHooks/actions/index.ts +117 -2
- package/reactHooks/cell-click/__tests__/index.test.js +64 -0
- package/reactHooks/cell-click/index.ts +39 -24
- package/reactHooks/connection/index.tsx +8 -5
- package/reactHooks/feed/__mocks__/useMarkPipesDataStale.ts +4 -0
- package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +25 -0
- package/reactHooks/feed/__tests__/useMarkPipesDataStale.test.tsx +243 -0
- package/reactHooks/feed/index.ts +5 -1
- package/reactHooks/feed/useBatchLoading.ts +9 -1
- package/reactHooks/feed/useMarkPipesDataStale.ts +97 -0
- package/reactHooks/index.ts +2 -0
- package/reactHooks/layout/index.ts +1 -1
- package/reactHooks/navigation/__mocks__/index.ts +4 -0
- package/reactHooks/navigation/__tests__/index.test.tsx +176 -1
- package/reactHooks/navigation/__tests__/useIsScreenActive.test.ts +42 -0
- package/reactHooks/navigation/__tests__/usePresentScreen.test.ts +154 -0
- package/reactHooks/navigation/index.ts +3 -1
- package/reactHooks/navigation/useIsScreenActive.ts +29 -8
- package/reactHooks/navigation/usePresentScreen.ts +157 -0
- package/reactHooks/navigation/useRoute.ts +22 -5
- package/reactHooks/state/useComponentScreenState.ts +1 -1
- package/reactHooks/usePluginConfiguration.ts +88 -47
- package/reactHooks/utils/__tests__/index.test.js +22 -2
- package/reactHooks/utils/index.ts +13 -2
- package/riverComponetsMeasurementProvider/index.tsx +15 -9
- package/stringUtils/__tests__/stringUtils.test.js +42 -0
- package/stringUtils/index.ts +2 -2
- package/uiActionsRegistrator/__tests__/resolveActionIdentifiers.test.ts +93 -0
- package/uiActionsRegistrator/__tests__/subscribe.test.ts +133 -0
- package/uiActionsRegistrator/__tests__/usableActionItems.test.ts +52 -0
- package/uiActionsRegistrator/index.ts +25 -0
- package/uiActionsRegistrator/registry.ts +351 -0
- package/uiActionsRegistrator/resolveActionIdentifiers.ts +100 -0
- package/uiActionsRegistrator/usableActionItems.ts +66 -0
- package/zappFrameworkUtils/__tests__/localStorageHelper.test.ts +146 -0
- package/zappFrameworkUtils/localStorageHelper.ts +19 -15
- package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +0 -56
- package/playerUtils/__tests__/getPlayerActionButtons.test.ts +0 -54
- package/playerUtils/getPlayerActionButtons.ts +0 -17
- package/reactHooks/feed/__mocks__/usePipesCacheReset.ts +0 -1
- package/reactHooks/feed/usePipesCacheReset.ts +0 -44
- /package/reactHooks/actions/__tests__/{index.test.js → index.test.tsx} +0 -0
package/cellUtils/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
import { dayjs } from "../dateUtils";
|
|
3
|
-
import validateColor from "validate-color";
|
|
4
3
|
|
|
4
|
+
import { isValidColor } from "@applicaster/zapp-react-native-utils/colorUtils";
|
|
5
5
|
import { transformColorCode as fixColorHexCode } from "@applicaster/zapp-react-native-utils/transform";
|
|
6
6
|
import {
|
|
7
7
|
capitalize,
|
|
@@ -12,6 +12,7 @@ import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
|
12
12
|
import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
13
13
|
|
|
14
14
|
import { toNumberWithDefault, toNumberWithDefaultZero } from "../numberUtils";
|
|
15
|
+
import { isTrue } from "../booleanUtils";
|
|
15
16
|
|
|
16
17
|
const CUSTOM_KEY = "other";
|
|
17
18
|
|
|
@@ -65,11 +66,38 @@ export const isEmptyOrNil = (value: any): boolean =>
|
|
|
65
66
|
*/
|
|
66
67
|
export const getLabel = (dataKeyValue, customDataKeyValue) => (entry) => {
|
|
67
68
|
const label = getKeyForLabel(dataKeyValue, customDataKeyValue);
|
|
68
|
-
const isPath = label &&
|
|
69
|
-
|
|
69
|
+
const isPath = label && label.length > 0;
|
|
70
|
+
|
|
71
|
+
// An unresolved key is rendered as-is, because a data key is allowed to be a
|
|
72
|
+
// literal label ("More") rather than a path. Fall back to the whole key
|
|
73
|
+
// instead of its first segment: "extensions.section" reads as an unresolved
|
|
74
|
+
// path, while "extensions" reads as a legitimate label and hides the problem.
|
|
75
|
+
const fallback = isEmptyOrNil(label) ? "" : label.join(".");
|
|
70
76
|
|
|
71
77
|
try {
|
|
72
|
-
|
|
78
|
+
if (!isPath) {
|
|
79
|
+
return fallback;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const resolved = label.reduce(
|
|
83
|
+
(value, key) => (value == null ? undefined : value[key]),
|
|
84
|
+
entry
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (isNotNil(resolved)) {
|
|
88
|
+
return resolved;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// A multi-segment key is unambiguously a path, so failing to resolve it is
|
|
92
|
+
// a misconfiguration rather than someone typing a literal label.
|
|
93
|
+
if (label.length > 1) {
|
|
94
|
+
cellUtilsLogger.warning({
|
|
95
|
+
message: `getLabel: data key "${fallback}" was not found on the entry, rendering the key itself`,
|
|
96
|
+
data: { dataKeyValue, customDataKeyValue, entryId: entry?.id },
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return fallback;
|
|
73
101
|
} catch (error) {
|
|
74
102
|
cellUtilsLogger.warning({
|
|
75
103
|
data: { error, dataKeyValue, customDataKeyValue },
|
|
@@ -468,15 +496,13 @@ export const getColorFromData = ({
|
|
|
468
496
|
data,
|
|
469
497
|
valueFromLayout,
|
|
470
498
|
}: GetColorFromData): string => {
|
|
471
|
-
|
|
472
|
-
// https://github.com/dreamyguy/validate-color/issues/44
|
|
473
|
-
if (validateColor(valueFromLayout.replace(".00", ""))) {
|
|
499
|
+
if (isValidColor(valueFromLayout)) {
|
|
474
500
|
return valueFromLayout;
|
|
475
501
|
}
|
|
476
502
|
|
|
477
503
|
const pathValue = R.path(valueFromLayout.split("."), data);
|
|
478
504
|
|
|
479
|
-
if (pathValue &&
|
|
505
|
+
if (pathValue && isValidColor(pathValue)) {
|
|
480
506
|
return pathValue;
|
|
481
507
|
}
|
|
482
508
|
|
|
@@ -547,3 +573,42 @@ export const hasTextLabelsEnabled = (
|
|
|
547
573
|
return Boolean(value);
|
|
548
574
|
});
|
|
549
575
|
};
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Reads the mobile buttons container "buttons enabled" switch from cell styles.
|
|
579
|
+
*/
|
|
580
|
+
export const getButtonsEnabled = (styles?: Record<string, any>): boolean => {
|
|
581
|
+
return isTrue(styles?.mobile_buttons_container_buttons_enabled);
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Reads the mobile buttons container "cell navigation enabled" switch from cell styles.
|
|
586
|
+
*/
|
|
587
|
+
export const getCellNavigationEnabled = (
|
|
588
|
+
styles?: Record<string, any>
|
|
589
|
+
): boolean => {
|
|
590
|
+
return isTrue(styles?.mobile_buttons_container_cell_navigation_enabled);
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Whether tapping a cell outside its action buttons triggers the cell's navigation.
|
|
595
|
+
* Always true when the buttons are disabled.
|
|
596
|
+
* @param buttonsEnabled the cell's "buttons enabled" switch value
|
|
597
|
+
* @param cellNavigationEnabled the cell's "cell navigation enabled" switch value
|
|
598
|
+
*/
|
|
599
|
+
export const isCellNavigationEnabled = (
|
|
600
|
+
buttonsEnabled: unknown,
|
|
601
|
+
cellNavigationEnabled: unknown
|
|
602
|
+
): boolean => !isTrue(buttonsEnabled) || isTrue(cellNavigationEnabled);
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Whether tapping a mobile cell outside its action buttons triggers the cell's navigation,
|
|
606
|
+
* read from the cell styles.
|
|
607
|
+
*/
|
|
608
|
+
export const getIsCellNavigationEnabled = (
|
|
609
|
+
styles?: Record<string, any>
|
|
610
|
+
): boolean =>
|
|
611
|
+
isCellNavigationEnabled(
|
|
612
|
+
getButtonsEnabled(styles),
|
|
613
|
+
getCellNavigationEnabled(styles)
|
|
614
|
+
);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { isTransparentColor } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isTransparentColor", () => {
|
|
4
|
+
it("returns true for transparent keyword and rgba colors with zero alpha", () => {
|
|
5
|
+
const transparentColors = [
|
|
6
|
+
"transparent",
|
|
7
|
+
"rgba(0,0,0,0)",
|
|
8
|
+
"rgba(255, 255, 255, 0)",
|
|
9
|
+
"rgba(0,0,0,0.0)",
|
|
10
|
+
"rgba(0,0,0,0.00)",
|
|
11
|
+
"rgba(0,0,0, 0)",
|
|
12
|
+
"hsla(0,0%,0%,0)",
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
expect.assertions(transparentColors.length);
|
|
16
|
+
|
|
17
|
+
transparentColors.forEach((color) => {
|
|
18
|
+
expect(isTransparentColor(color)).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("returns false for valid colors that are not fully transparent", () => {
|
|
23
|
+
const nonTransparentColors = [
|
|
24
|
+
"red",
|
|
25
|
+
"#fff",
|
|
26
|
+
"#ffffff",
|
|
27
|
+
"rgb(0,0,0)",
|
|
28
|
+
"rgba(0,0,0)",
|
|
29
|
+
"rgba(0,0,0,0.5)",
|
|
30
|
+
"rgba(255, 255, 255, 0.3)",
|
|
31
|
+
"rgba(255, 255, 255, 1.0)",
|
|
32
|
+
"rgba(239,239,239,1.0)",
|
|
33
|
+
"currentColor",
|
|
34
|
+
"inherit",
|
|
35
|
+
"#00000000",
|
|
36
|
+
"#fff0",
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
expect.assertions(nonTransparentColors.length);
|
|
40
|
+
|
|
41
|
+
nonTransparentColors.forEach((color) => {
|
|
42
|
+
expect(isTransparentColor(color)).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns false for case variants of the transparent keyword", () => {
|
|
47
|
+
expect(isTransparentColor("Transparent")).toBe(false);
|
|
48
|
+
expect(isTransparentColor("TRANSPARENT")).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("returns false for invalid color strings", () => {
|
|
52
|
+
const invalidColors = [
|
|
53
|
+
"invalid",
|
|
54
|
+
"",
|
|
55
|
+
"#gggggg",
|
|
56
|
+
"#fff.00",
|
|
57
|
+
"unset",
|
|
58
|
+
" rgba(0,0,0,0) ",
|
|
59
|
+
"transparent ",
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
expect.assertions(invalidColors.length);
|
|
63
|
+
|
|
64
|
+
invalidColors.forEach((color) => {
|
|
65
|
+
expect(isTransparentColor(color)).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("returns false for nullish and non-string values", () => {
|
|
70
|
+
expect(isTransparentColor(undefined)).toBe(false);
|
|
71
|
+
expect(isTransparentColor(null)).toBe(false);
|
|
72
|
+
expect(isTransparentColor(123)).toBe(false);
|
|
73
|
+
expect(isTransparentColor({})).toBe(false);
|
|
74
|
+
expect(isTransparentColor([])).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { isValidColor } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isValidColor", () => {
|
|
4
|
+
it("returns true for valid hex colors", () => {
|
|
5
|
+
const validHexColors = ["#fff", "#ffffff", "#FF0000", "#000", "#abc123"];
|
|
6
|
+
|
|
7
|
+
expect.assertions(validHexColors.length);
|
|
8
|
+
|
|
9
|
+
validHexColors.forEach((color) => {
|
|
10
|
+
expect(isValidColor(color)).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("returns true for valid rgb and rgba colors", () => {
|
|
15
|
+
const validRgbColors = [
|
|
16
|
+
"rgb(255,0,0)",
|
|
17
|
+
"rgb(255, 0, 0)",
|
|
18
|
+
"rgba(255,0,0,0.5)",
|
|
19
|
+
"rgba(255, 0, 0, 0.5)",
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
expect.assertions(validRgbColors.length);
|
|
23
|
+
|
|
24
|
+
validRgbColors.forEach((color) => {
|
|
25
|
+
expect(isValidColor(color)).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("returns true for valid named and special CSS colors", () => {
|
|
30
|
+
const validNamedColors = ["red", "transparent", "currentColor", "inherit"];
|
|
31
|
+
|
|
32
|
+
expect.assertions(validNamedColors.length);
|
|
33
|
+
|
|
34
|
+
validNamedColors.forEach((color) => {
|
|
35
|
+
expect(isValidColor(color)).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("returns true for valid hsl colors", () => {
|
|
40
|
+
expect(isValidColor("hsl(0, 100%, 50%)")).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("returns false for invalid color strings", () => {
|
|
44
|
+
const invalidColors = [
|
|
45
|
+
"invalid",
|
|
46
|
+
"",
|
|
47
|
+
"#gggggg",
|
|
48
|
+
"#fff.00",
|
|
49
|
+
"unset",
|
|
50
|
+
undefined,
|
|
51
|
+
null,
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
expect.assertions(invalidColors.length);
|
|
55
|
+
|
|
56
|
+
invalidColors.forEach((color) => {
|
|
57
|
+
expect(isValidColor(color)).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("returns true for valid rgb and rgba colors", () => {
|
|
62
|
+
const validRgbColors = ["rgba(239,239,239,1.0)"];
|
|
63
|
+
|
|
64
|
+
expect.assertions(validRgbColors.length);
|
|
65
|
+
|
|
66
|
+
validRgbColors.forEach((color) => {
|
|
67
|
+
expect(isValidColor(color)).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import validateColor from "validate-color";
|
|
2
|
+
import { isNil } from "@applicaster/zapp-react-native-utils/utils";
|
|
3
|
+
import { isString } from "@applicaster/zapp-react-native-utils/stringUtils";
|
|
4
|
+
|
|
5
|
+
const normalizeRgbaAlpha = (color: string): string => {
|
|
6
|
+
return color.replace(
|
|
7
|
+
/^rgba\(([^)]+),\s*(\d+(?:\.\d+)?)\s*\)$/i,
|
|
8
|
+
(_, rgb, alpha) => {
|
|
9
|
+
const alphaValue = parseFloat(alpha);
|
|
10
|
+
|
|
11
|
+
if (!Number.isFinite(alphaValue) || !Number.isInteger(alphaValue)) {
|
|
12
|
+
return color;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return `rgba(${rgb},${alphaValue})`;
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const isValidColor = (color: string): boolean => {
|
|
21
|
+
if (isNil(color) || !isString(color)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (validateColor(color)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// validate-color rejects integer alpha values written as floats (e.g. 1.0)
|
|
30
|
+
// https://github.com/dreamyguy/validate-color/issues/44
|
|
31
|
+
const normalizedColor = normalizeRgbaAlpha(color);
|
|
32
|
+
|
|
33
|
+
return normalizedColor !== color && validateColor(normalizedColor);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function isRgbaAlphaZero(color: string): boolean {
|
|
37
|
+
const layers = color
|
|
38
|
+
.replace("rgba(", "")
|
|
39
|
+
.replace(")", "")
|
|
40
|
+
.split(",")
|
|
41
|
+
.map((layer) => layer.trim());
|
|
42
|
+
|
|
43
|
+
return Number(layers[3]) === 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const isTransparentColor = (color: string): boolean => {
|
|
47
|
+
return (
|
|
48
|
+
isValidColor(color) && (color === "transparent" || isRgbaAlphaZero(color))
|
|
49
|
+
);
|
|
50
|
+
};
|
|
@@ -176,6 +176,27 @@ describe("getAllSpecificStyles", () => {
|
|
|
176
176
|
});
|
|
177
177
|
});
|
|
178
178
|
|
|
179
|
+
it("should normalize Studio focus alias onto focused state", () => {
|
|
180
|
+
const outStyles = {};
|
|
181
|
+
|
|
182
|
+
const configuration = {
|
|
183
|
+
button_style_focus_background_color: "#FF3B30",
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
getAllSpecificStyles({
|
|
187
|
+
componentName: "button",
|
|
188
|
+
subComponentName: "",
|
|
189
|
+
configuration,
|
|
190
|
+
outStyles,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(outStyles.focused).toEqual({
|
|
194
|
+
backgroundColor: "#FF3B30",
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
expect(outStyles.focus).toBeUndefined();
|
|
198
|
+
});
|
|
199
|
+
|
|
179
200
|
it("should handle selected state", () => {
|
|
180
201
|
const outStyles = {};
|
|
181
202
|
|