@applicaster/zapp-react-native-utils 15.1.0-rc.1 → 16.0.0-rc.1

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 (144) hide show
  1. package/README.md +0 -6
  2. package/actionUtils/index.ts +7 -0
  3. package/actionsExecutor/ActionExecutorContext.tsx +43 -12
  4. package/actionsExecutor/feedDecorator.ts +6 -6
  5. package/adsUtils/__tests__/createVMAP.test.ts +419 -0
  6. package/adsUtils/index.ts +2 -2
  7. package/analyticsUtils/README.md +1 -1
  8. package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
  9. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
  10. package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
  11. package/appUtils/HooksManager/index.ts +10 -10
  12. package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
  13. package/appUtils/accessibilityManager/const.ts +4 -0
  14. package/appUtils/accessibilityManager/utils.ts +0 -1
  15. package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
  16. package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
  17. package/appUtils/contextKeysManager/contextResolver.ts +51 -22
  18. package/appUtils/contextKeysManager/index.ts +65 -10
  19. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -0
  20. package/appUtils/focusManager/index.ios.ts +43 -4
  21. package/appUtils/focusManager/treeDataStructure/Tree/__tests__/Tree.test.js +46 -0
  22. package/appUtils/focusManager/treeDataStructure/Tree/index.js +18 -18
  23. package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
  24. package/appUtils/focusManagerAux/utils/index.ts +11 -3
  25. package/appUtils/focusManagerAux/utils/utils.ios.ts +202 -3
  26. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  27. package/appUtils/orientationHelper.ts +2 -4
  28. package/appUtils/platform/platformUtils.ts +1 -1
  29. package/appUtils/playerManager/player.ts +4 -0
  30. package/appUtils/playerManager/playerNative.ts +30 -21
  31. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  32. package/cloudEventsUtils/__tests__/index.test.ts +529 -0
  33. package/cloudEventsUtils/index.ts +65 -1
  34. package/componentsUtils/index.ts +8 -0
  35. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  36. package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
  37. package/errorUtils/__tests__/GeneralError.test.ts +97 -0
  38. package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
  39. package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
  40. package/errorUtils/__tests__/NetworkError.test.ts +202 -0
  41. package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
  42. package/errorUtils/__tests__/invariant.test.ts +112 -0
  43. package/focusManager/aux/index.ts +1 -1
  44. package/headersUtils/__tests__/headersUtils.test.js +11 -1
  45. package/headersUtils/index.ts +2 -1
  46. package/manifestUtils/_internals/__tests__/index.test.js +41 -0
  47. package/manifestUtils/_internals/index.js +33 -0
  48. package/manifestUtils/defaultManifestConfigurations/player.js +59 -1
  49. package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +49 -0
  50. package/manifestUtils/fieldUtils/index.js +54 -0
  51. package/manifestUtils/index.js +2 -0
  52. package/manifestUtils/keys.js +228 -0
  53. package/manifestUtils/mobileAction/button/__tests__/mobileActionButton.test.js +168 -0
  54. package/manifestUtils/mobileAction/button/index.js +140 -0
  55. package/manifestUtils/mobileAction/container/__tests__/mobileActionButtonsContainer.test.js +102 -0
  56. package/manifestUtils/mobileAction/container/index.js +73 -0
  57. package/manifestUtils/mobileAction/groups/__tests__/buildMobileActionButtonGroups.test.js +127 -0
  58. package/manifestUtils/mobileAction/groups/defaults.js +76 -0
  59. package/manifestUtils/mobileAction/groups/index.js +80 -0
  60. package/manifestUtils/tvAction/container/index.js +1 -1
  61. package/numberUtils/__tests__/toNumber.test.ts +27 -0
  62. package/numberUtils/__tests__/toPositiveNumber.test.ts +193 -0
  63. package/numberUtils/index.ts +23 -1
  64. package/package.json +4 -4
  65. package/pluginUtils/index.ts +4 -0
  66. package/reactHooks/advertising/index.ts +2 -2
  67. package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
  68. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  69. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  70. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  71. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  72. package/reactHooks/cell-click/index.ts +2 -1
  73. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  74. package/reactHooks/connection/__tests__/index.test.js +1 -1
  75. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  76. package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
  77. package/reactHooks/device/useIsTablet.tsx +14 -19
  78. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  79. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  80. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  81. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
  82. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  83. package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +1 -1
  84. package/reactHooks/feed/index.ts +0 -2
  85. package/reactHooks/feed/useBatchLoading.ts +7 -1
  86. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  87. package/reactHooks/feed/usePipesCacheReset.ts +3 -1
  88. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  89. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  90. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  91. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  92. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  93. package/reactHooks/navigation/__tests__/index.test.tsx +2 -4
  94. package/reactHooks/navigation/index.ts +7 -6
  95. package/reactHooks/navigation/useRoute.ts +8 -6
  96. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  97. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  98. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  99. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  100. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  101. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  102. package/reactHooks/resolvers/useComponentResolver.ts +8 -2
  103. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
  104. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  105. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  106. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
  107. package/reactHooks/screen/index.ts +0 -2
  108. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  109. package/reactHooks/state/useRivers.ts +1 -1
  110. package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
  111. package/reactHooks/usePluginConfiguration.ts +2 -2
  112. package/reactHooks/utils/__tests__/index.test.js +1 -1
  113. package/rectUtils/__tests__/index.test.ts +549 -0
  114. package/rectUtils/index.ts +2 -2
  115. package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +206 -0
  116. package/refreshUtils/RefreshCoordinator/index.ts +245 -0
  117. package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
  118. package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
  119. package/screenPickerUtils/__tests__/index.test.ts +333 -0
  120. package/screenState/__tests__/index.test.ts +1 -1
  121. package/screenUtils/index.ts +3 -0
  122. package/searchUtils/const.ts +7 -0
  123. package/searchUtils/index.ts +3 -0
  124. package/stringUtils/index.ts +1 -1
  125. package/testUtils/index.tsx +30 -21
  126. package/time/__tests__/BackgroundTimer.test.ts +156 -0
  127. package/time/__tests__/Timer.test.ts +236 -0
  128. package/typeGuards/__tests__/isString.test.ts +21 -0
  129. package/typeGuards/index.ts +4 -0
  130. package/utils/__tests__/mergeRight.test.ts +48 -0
  131. package/utils/__tests__/path.test.ts +7 -0
  132. package/utils/__tests__/selectors.test.ts +124 -0
  133. package/utils/index.ts +13 -0
  134. package/utils/mergeRight.ts +5 -0
  135. package/utils/path.ts +6 -3
  136. package/utils/pathOr.ts +5 -1
  137. package/utils/selectors.ts +46 -0
  138. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +1 -1
  139. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
  140. package/zappFrameworkUtils/loginPluginUtils.ts +1 -1
  141. package/reactHooks/componentsMap/index.ts +0 -55
  142. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
  143. package/reactHooks/feed/useFeedRefresh.tsx +0 -65
  144. package/reactHooks/screen/useIsStandaloneFullscreen.ts +0 -12
@@ -406,6 +406,232 @@ const TV_ACTION_BUTTON_FIELDS = [
406
406
  },
407
407
  ];
408
408
 
409
+ const mobileActionButtonContainerFields = (positionOptions) => [
410
+ {
411
+ type: ZAPPIFEST_FIELDS.switch,
412
+ suffix: "buttons enabled",
413
+ },
414
+ {
415
+ type: ZAPPIFEST_FIELDS.select,
416
+ suffix: "position",
417
+ options: positionOptions,
418
+ },
419
+ {
420
+ type: ZAPPIFEST_FIELDS.select,
421
+ suffix: "align",
422
+ options: ["left", "center", "right"],
423
+ },
424
+ {
425
+ type: ZAPPIFEST_FIELDS.select,
426
+ suffix: "over image position",
427
+ options: ["center", "top_left", "top_right", "bottom_left", "bottom_right"],
428
+ },
429
+ {
430
+ type: ZAPPIFEST_FIELDS.number_input,
431
+ suffix: "margin top",
432
+ },
433
+ {
434
+ type: ZAPPIFEST_FIELDS.number_input,
435
+ suffix: "margin right",
436
+ },
437
+ {
438
+ type: ZAPPIFEST_FIELDS.number_input,
439
+ suffix: "margin bottom",
440
+ },
441
+ {
442
+ type: ZAPPIFEST_FIELDS.number_input,
443
+ suffix: "margin left",
444
+ },
445
+ {
446
+ type: ZAPPIFEST_FIELDS.select,
447
+ suffix: "stacking",
448
+ options: ["horizontal", "vertical"],
449
+ },
450
+ {
451
+ type: ZAPPIFEST_FIELDS.number_input,
452
+ suffix: "horizontal gutter",
453
+ },
454
+ {
455
+ type: ZAPPIFEST_FIELDS.number_input,
456
+ suffix: "vertical gutter",
457
+ },
458
+ {
459
+ type: ZAPPIFEST_FIELDS.switch,
460
+ suffix: "independent styles",
461
+ },
462
+ ];
463
+
464
+ const MOBILE_ACTION_BUTTON_FIELDS = [
465
+ {
466
+ type: ZAPPIFEST_FIELDS.switch,
467
+ suffix: "button enabled",
468
+ },
469
+ {
470
+ type: ZAPPIFEST_FIELDS.select,
471
+ suffix: "assign action",
472
+ options: [
473
+ { text: "primary navigation", value: "navigation_action" },
474
+ { text: "secondary navigation", value: "secondary_navigation" },
475
+ { text: "favorite", value: "local_storage_favourites_action" },
476
+ { text: "more", value: "open-modal-bottom-sheet-cell-action" },
477
+ { text: "add to calendar", value: "add_to_calendar_action" },
478
+ { text: "share", value: "native_share_action" },
479
+ { text: "downloads", value: "offline-content-button" },
480
+ { text: "trailer", value: "trailer_action" },
481
+ { text: "mute/unmute", value: "mute_unmute" },
482
+ ],
483
+ },
484
+ {
485
+ type: ZAPPIFEST_FIELDS.select,
486
+ suffix: "display mode",
487
+ options: ["dynamic", "fixed", "fill"],
488
+ },
489
+ {
490
+ type: ZAPPIFEST_FIELDS.number_input,
491
+ suffix: "width",
492
+ },
493
+ {
494
+ type: ZAPPIFEST_FIELDS.select,
495
+ suffix: "contents alignment",
496
+ options: ["left", "center", "right"],
497
+ },
498
+ {
499
+ type: ZAPPIFEST_FIELDS.color_picker,
500
+ suffix: "background color",
501
+ },
502
+ {
503
+ type: ZAPPIFEST_FIELDS.color_picker,
504
+ suffix: "focused background color",
505
+ },
506
+ {
507
+ type: ZAPPIFEST_FIELDS.color_picker,
508
+ suffix: "border color",
509
+ },
510
+ {
511
+ type: ZAPPIFEST_FIELDS.color_picker,
512
+ suffix: "focused border color",
513
+ },
514
+ {
515
+ type: ZAPPIFEST_FIELDS.number_input,
516
+ suffix: "border size",
517
+ },
518
+ {
519
+ type: ZAPPIFEST_FIELDS.number_input,
520
+ suffix: "corner radius",
521
+ },
522
+ {
523
+ type: ZAPPIFEST_FIELDS.number_input,
524
+ suffix: "padding top",
525
+ },
526
+ {
527
+ type: ZAPPIFEST_FIELDS.number_input,
528
+ suffix: "padding right",
529
+ },
530
+ {
531
+ type: ZAPPIFEST_FIELDS.number_input,
532
+ suffix: "padding bottom",
533
+ },
534
+ {
535
+ type: ZAPPIFEST_FIELDS.number_input,
536
+ suffix: "padding left",
537
+ },
538
+ {
539
+ type: ZAPPIFEST_FIELDS.switch,
540
+ suffix: "asset enabled",
541
+ },
542
+ {
543
+ type: ZAPPIFEST_FIELDS.select,
544
+ suffix: "action asset flavour",
545
+ options: ["flavour_1", "flavour_2"],
546
+ },
547
+ {
548
+ type: ZAPPIFEST_FIELDS.select,
549
+ suffix: "asset alignment",
550
+ options: ["left", "right", "above", "below"],
551
+ },
552
+ {
553
+ type: ZAPPIFEST_FIELDS.number_input,
554
+ suffix: "asset height",
555
+ },
556
+ {
557
+ type: ZAPPIFEST_FIELDS.number_input,
558
+ suffix: "asset width",
559
+ },
560
+ {
561
+ type: ZAPPIFEST_FIELDS.number_input,
562
+ suffix: "asset margin top",
563
+ },
564
+ {
565
+ type: ZAPPIFEST_FIELDS.number_input,
566
+ suffix: "asset margin right",
567
+ },
568
+ {
569
+ type: ZAPPIFEST_FIELDS.number_input,
570
+ suffix: "asset margin bottom",
571
+ },
572
+ {
573
+ type: ZAPPIFEST_FIELDS.number_input,
574
+ suffix: "asset margin left",
575
+ },
576
+ {
577
+ type: ZAPPIFEST_FIELDS.switch,
578
+ suffix: "label enabled",
579
+ },
580
+ {
581
+ type: ZAPPIFEST_FIELDS.color_picker,
582
+ suffix: "font color",
583
+ },
584
+ {
585
+ type: ZAPPIFEST_FIELDS.color_picker,
586
+ suffix: "focused font color",
587
+ },
588
+ {
589
+ type: ZAPPIFEST_FIELDS.font_selector.ios,
590
+ suffix: "iOS font family",
591
+ },
592
+ {
593
+ type: ZAPPIFEST_FIELDS.font_selector.android,
594
+ suffix: "android font family",
595
+ },
596
+ {
597
+ type: ZAPPIFEST_FIELDS.number_input,
598
+ suffix: "font size",
599
+ },
600
+ {
601
+ type: ZAPPIFEST_FIELDS.number_input,
602
+ suffix: "line height",
603
+ },
604
+ {
605
+ type: ZAPPIFEST_FIELDS.number_input,
606
+ suffix: "iOS letter spacing",
607
+ },
608
+ {
609
+ type: ZAPPIFEST_FIELDS.number_input,
610
+ suffix: "android letter spacing",
611
+ },
612
+ {
613
+ type: ZAPPIFEST_FIELDS.select,
614
+ suffix: "text transform",
615
+ options: ["default", "lowercase", "uppercase", "capitalize"],
616
+ },
617
+ {
618
+ type: ZAPPIFEST_FIELDS.number_input,
619
+ suffix: "margin top",
620
+ },
621
+ {
622
+ type: ZAPPIFEST_FIELDS.number_input,
623
+ suffix: "margin right",
624
+ },
625
+ {
626
+ type: ZAPPIFEST_FIELDS.number_input,
627
+ suffix: "margin bottom",
628
+ },
629
+ {
630
+ type: ZAPPIFEST_FIELDS.number_input,
631
+ suffix: "margin left",
632
+ },
633
+ ];
634
+
409
635
  const TV_MENU_LABEL_FIELDS = [
410
636
  {
411
637
  type: ZAPPIFEST_FIELDS.switch,
@@ -2134,6 +2360,8 @@ module.exports = {
2134
2360
  TV_COLOR_STATES,
2135
2361
  TV_ACTION_BUTTON_FIELDS,
2136
2362
  tvActionButtonContainerFields,
2363
+ MOBILE_ACTION_BUTTON_FIELDS,
2364
+ mobileActionButtonContainerFields,
2137
2365
  MOBILE_CELL_LABEL_FIELDS,
2138
2366
  TV_CELL_LABEL_FIELDS,
2139
2367
  TV_CELL_BADGE_FIELDS,
@@ -0,0 +1,168 @@
1
+ import { mobileActionButton } from "..";
2
+
3
+ describe("mobileActionButton", () => {
4
+ const defaults = {
5
+ buttonEnabled: true,
6
+ assignAction: "navigation_action",
7
+ displayMode: "dynamic",
8
+ width: 140,
9
+ contentsAlignment: "center",
10
+ backgroundColor: "rgba(1,1,1,1)",
11
+ focusedBackgroundColor: "rgba(2,2,2,1)",
12
+ borderColor: "rgba(0,0,0,0)",
13
+ focusedBorderColor: "rgba(0,0,0,0)",
14
+ borderSize: 0,
15
+ cornerRadius: 8,
16
+ paddingTop: 14,
17
+ paddingRight: 24,
18
+ paddingBottom: 14,
19
+ paddingLeft: 16,
20
+ assetEnabled: true,
21
+ actionAssetFlavour: "flavour_1",
22
+ assetAlignment: "left",
23
+ assetHeight: 24,
24
+ assetWidth: 24,
25
+ assetMarginTop: 0,
26
+ assetMarginRight: 6,
27
+ assetMarginBottom: 0,
28
+ assetMarginLeft: 0,
29
+ labelEnabled: true,
30
+ fontColor: "rgba(239,239,239,1)",
31
+ focusedFontColor: "rgba(239,239,239,1)",
32
+ iosFontFamily: "Ubuntu-Bold",
33
+ androidFontFamily: "Ubuntu-Bold",
34
+ fontSize: 15,
35
+ lineHeight: 24,
36
+ iosLetterSpacing: -0.2,
37
+ androidLetterSpacing: -0.2,
38
+ textTransform: "default",
39
+ marginTop: 0,
40
+ marginRight: 0,
41
+ marginBottom: 0,
42
+ marginLeft: 0,
43
+ };
44
+
45
+ it("generates button fields with inferred conditional rules", () => {
46
+ const result = mobileActionButton({
47
+ label: "Mobile Button 2",
48
+ description: "button 2",
49
+ defaults,
50
+ isFirstButton: false,
51
+ });
52
+
53
+ expect(result.group).toBe(true);
54
+
55
+ const enabledField = result.fields.find(
56
+ (field) => field.key === "mobile_button_2_button_enabled"
57
+ );
58
+
59
+ expect(enabledField).toBeTruthy();
60
+
61
+ expect(enabledField.conditional_fields).toEqual([
62
+ {
63
+ key: "styles/mobile_buttons_container_buttons_enabled",
64
+ condition_value: true,
65
+ },
66
+ ]);
67
+
68
+ const assignActionField = result.fields.find(
69
+ (field) => field.key === "mobile_button_2_assign_action"
70
+ );
71
+
72
+ expect(assignActionField).toBeTruthy();
73
+
74
+ expect(assignActionField.conditional_fields).toEqual([
75
+ {
76
+ key: "styles/mobile_button_2_button_enabled",
77
+ condition_value: true,
78
+ },
79
+ ]);
80
+
81
+ const widthField = result.fields.find(
82
+ (field) => field.key === "mobile_button_2_width"
83
+ );
84
+
85
+ expect(widthField.rules).toBe("all_conditions");
86
+
87
+ expect(widthField.conditional_fields).toEqual([
88
+ {
89
+ key: "styles/mobile_button_2_button_enabled",
90
+ condition_value: true,
91
+ },
92
+ {
93
+ key: "styles/mobile_buttons_container_independent_styles",
94
+ condition_value: true,
95
+ },
96
+ {
97
+ key: "styles/mobile_button_2_display_mode",
98
+ condition_value: "fixed",
99
+ },
100
+ ]);
101
+
102
+ const actionAssetFlavourField = result.fields.find(
103
+ (field) => field.key === "mobile_button_2_action_asset_flavour"
104
+ );
105
+
106
+ expect(actionAssetFlavourField.rules).toBe("all_conditions");
107
+
108
+ expect(actionAssetFlavourField.conditional_fields).toEqual([
109
+ {
110
+ key: "styles/mobile_button_2_button_enabled",
111
+ condition_value: true,
112
+ },
113
+ {
114
+ key: "styles/mobile_buttons_container_independent_styles",
115
+ condition_value: true,
116
+ },
117
+ {
118
+ key: "styles/mobile_button_2_asset_enabled",
119
+ condition_value: true,
120
+ },
121
+ ]);
122
+
123
+ const contentsAlignmentField = result.fields.find(
124
+ (field) => field.key === "mobile_button_2_contents_alignment"
125
+ );
126
+
127
+ expect(contentsAlignmentField.rules).toBe("all_conditions");
128
+
129
+ expect(contentsAlignmentField.conditional_fields).toEqual([
130
+ {
131
+ key: "styles/mobile_button_2_button_enabled",
132
+ condition_value: true,
133
+ },
134
+ {
135
+ key: "styles/mobile_buttons_container_independent_styles",
136
+ condition_value: true,
137
+ },
138
+ {
139
+ key: "styles/mobile_button_2_display_mode",
140
+ condition_value: ["fixed", "fill"],
141
+ },
142
+ ]);
143
+ });
144
+
145
+ it("keeps first-button fields independent-style agnostic", () => {
146
+ const result = mobileActionButton({
147
+ label: "Mobile Button 1",
148
+ description: "button 1",
149
+ defaults,
150
+ isFirstButton: true,
151
+ });
152
+
153
+ const widthField = result.fields.find(
154
+ (field) => field.key === "mobile_button_1_width"
155
+ );
156
+
157
+ expect(widthField.conditional_fields).toEqual([
158
+ {
159
+ key: "styles/mobile_button_1_button_enabled",
160
+ condition_value: true,
161
+ },
162
+ {
163
+ key: "styles/mobile_button_1_display_mode",
164
+ condition_value: "fixed",
165
+ },
166
+ ]);
167
+ });
168
+ });
@@ -0,0 +1,140 @@
1
+ const { MOBILE_ACTION_BUTTON_FIELDS } = require("../../keys");
2
+
3
+ const {
4
+ isKeyHasSuffix,
5
+ toSnakeCase,
6
+ generateFieldsFromDefaultsWithoutPrefixedLabel,
7
+ getKeyWithPrefixGenerator,
8
+ isKeyHasAnyOfSuffixes,
9
+ } = require("../../_internals");
10
+
11
+ const { withConditional, createConditionalField } = require("../../fieldUtils");
12
+
13
+ const { fieldsGroup } = require("../../utils");
14
+
15
+ /**
16
+ * Builds a manifest group for a single mobile action button and applies the
17
+ * conditional visibility rules between container, button, asset, and label fields.
18
+ *
19
+ * @param {object} options
20
+ * @param {string} options.label
21
+ * @param {string} options.description
22
+ * @param {object} options.defaults
23
+ * @param {boolean} options.isFirstButton
24
+ * @returns {object}
25
+ */
26
+ function mobileActionButton({ label, description, defaults, isFirstButton }) {
27
+ const buttonKeyFromLabel = toSnakeCase(label); // "Mobile Button 1" -> "mobile_button_1"
28
+
29
+ const generatedFields = generateFieldsFromDefaultsWithoutPrefixedLabel(
30
+ label,
31
+ defaults,
32
+ MOBILE_ACTION_BUTTON_FIELDS
33
+ );
34
+
35
+ const keyPrefixGenerator = getKeyWithPrefixGenerator(buttonKeyFromLabel);
36
+
37
+ const containerKeyPrefixGenerator = getKeyWithPrefixGenerator(
38
+ "mobile_buttons_container"
39
+ );
40
+
41
+ const containerEnabledKey = containerKeyPrefixGenerator("buttons_enabled");
42
+
43
+ const independentStylesKey =
44
+ containerKeyPrefixGenerator("independent_styles");
45
+
46
+ const buttonEnabledKey = keyPrefixGenerator("button_enabled");
47
+ const displayModeKey = keyPrefixGenerator("display_mode");
48
+ const assetEnabledKey = keyPrefixGenerator("asset_enabled");
49
+ const labelEnabledKey = keyPrefixGenerator("label_enabled");
50
+
51
+ const defaultButtonConditions = [
52
+ createConditionalField(buttonEnabledKey, true),
53
+ ];
54
+
55
+ const fields = generatedFields.map((field) => {
56
+ const key = field.key;
57
+
58
+ // button_enabled has to be always visible when the container is enabled, as it's the main toggle for the button
59
+ if (isKeyHasSuffix("button_enabled", key)) {
60
+ return withConditional([
61
+ createConditionalField(containerEnabledKey, true),
62
+ ])(field);
63
+ }
64
+
65
+ // for button at index 1(isFirstButton) return `defaultButtonsConditions`,
66
+ // the rest buttons lookup depends on independent styles toggle
67
+ const stylesConditions = isFirstButton
68
+ ? defaultButtonConditions
69
+ : [
70
+ ...defaultButtonConditions,
71
+ createConditionalField(independentStylesKey, true),
72
+ ];
73
+
74
+ // assign_action depends only on button_enabled
75
+ if (isKeyHasSuffix("assign_action", key)) {
76
+ return withConditional(defaultButtonConditions)(field);
77
+ }
78
+
79
+ const conditions = [...stylesConditions];
80
+
81
+ // width depends on [display_mode: fixed]
82
+ if (isKeyHasSuffix("width", key)) {
83
+ conditions.push(createConditionalField(displayModeKey, "fixed"));
84
+ }
85
+
86
+ // contents_alignment depends on [display_mode: fixed or display_mode: fill]
87
+ if (isKeyHasSuffix("contents_alignment", key)) {
88
+ conditions.push(
89
+ createConditionalField(displayModeKey, ["fixed", "fill"])
90
+ );
91
+ }
92
+
93
+ // asset styling fields depend on [asset_enabled: true]
94
+ if (
95
+ isKeyHasAnyOfSuffixes(
96
+ [
97
+ "action_asset_flavour",
98
+ "asset_alignment",
99
+ "asset_height",
100
+ "asset_width",
101
+ "asset_margin_top",
102
+ "asset_margin_right",
103
+ "asset_margin_bottom",
104
+ "asset_margin_left",
105
+ ],
106
+ key
107
+ )
108
+ ) {
109
+ conditions.push(createConditionalField(assetEnabledKey, true));
110
+ }
111
+
112
+ // label styling fields depend on [label_enabled: true]
113
+ if (
114
+ isKeyHasAnyOfSuffixes(
115
+ [
116
+ "font_color",
117
+ "focused_font_color",
118
+ "ios_font_family",
119
+ "android_font_family",
120
+ "font_size",
121
+ "line_height",
122
+ "ios_letter_spacing",
123
+ "android_letter_spacing",
124
+ "text_transform",
125
+ ],
126
+ key
127
+ )
128
+ ) {
129
+ conditions.push(createConditionalField(labelEnabledKey, true));
130
+ }
131
+
132
+ return withConditional(conditions)(field);
133
+ });
134
+
135
+ return fieldsGroup(label, description, fields);
136
+ }
137
+
138
+ module.exports = {
139
+ mobileActionButton,
140
+ };
@@ -0,0 +1,102 @@
1
+ import { mobileActionButtonsContainer } from "..";
2
+
3
+ describe("mobileActionButtonsContainer", () => {
4
+ it("generates container fields with inferred conditionals", () => {
5
+ const result = mobileActionButtonsContainer({
6
+ label: "Mobile Buttons Container",
7
+ description: "container",
8
+ defaults: {
9
+ buttonsEnabled: false,
10
+ position: ["over_image", "text_label_1", "text_label_2"],
11
+ align: "left",
12
+ overImagePosition: "bottom_left",
13
+ marginTop: 0,
14
+ marginRight: 20,
15
+ marginBottom: 0,
16
+ marginLeft: 20,
17
+ stacking: "horizontal",
18
+ horizontalGutter: 8,
19
+ verticalGutter: 8,
20
+ independentStyles: true,
21
+ },
22
+ });
23
+
24
+ expect(result.group).toBe(true);
25
+ expect(result.label).toBe("Mobile Buttons Container");
26
+
27
+ const enabledField = result.fields.find(
28
+ (field) => field.key === "mobile_buttons_container_buttons_enabled"
29
+ );
30
+
31
+ expect(enabledField).toBeTruthy();
32
+ expect(enabledField.type).toBe("switch");
33
+
34
+ const positionField = result.fields.find(
35
+ (field) => field.key === "mobile_buttons_container_position"
36
+ );
37
+
38
+ expect(positionField.options).toEqual([
39
+ "over_image",
40
+ "text_label_1",
41
+ "text_label_2",
42
+ ]);
43
+
44
+ expect(positionField.conditional_fields).toEqual([
45
+ {
46
+ key: "styles/mobile_buttons_container_buttons_enabled",
47
+ condition_value: true,
48
+ },
49
+ ]);
50
+
51
+ const overImagePositionField = result.fields.find(
52
+ (field) => field.key === "mobile_buttons_container_over_image_position"
53
+ );
54
+
55
+ expect(overImagePositionField.rules).toBe("all_conditions");
56
+
57
+ expect(overImagePositionField.conditional_fields).toEqual([
58
+ {
59
+ key: "styles/mobile_buttons_container_buttons_enabled",
60
+ condition_value: true,
61
+ },
62
+ {
63
+ key: "styles/mobile_buttons_container_position",
64
+ condition_value: "over_image",
65
+ },
66
+ ]);
67
+
68
+ const horizontalGutterField = result.fields.find(
69
+ (field) => field.key === "mobile_buttons_container_horizontal_gutter"
70
+ );
71
+
72
+ expect(horizontalGutterField.rules).toBe("all_conditions");
73
+
74
+ expect(horizontalGutterField.conditional_fields).toEqual([
75
+ {
76
+ key: "styles/mobile_buttons_container_buttons_enabled",
77
+ condition_value: true,
78
+ },
79
+ {
80
+ key: "styles/mobile_buttons_container_stacking",
81
+ condition_value: "horizontal",
82
+ },
83
+ ]);
84
+
85
+ const verticalGutterField = result.fields.find(
86
+ (field) => field.key === "mobile_buttons_container_vertical_gutter"
87
+ );
88
+
89
+ expect(verticalGutterField.rules).toBe("all_conditions");
90
+
91
+ expect(verticalGutterField.conditional_fields).toEqual([
92
+ {
93
+ key: "styles/mobile_buttons_container_buttons_enabled",
94
+ condition_value: true,
95
+ },
96
+ {
97
+ key: "styles/mobile_buttons_container_stacking",
98
+ condition_value: "vertical",
99
+ },
100
+ ]);
101
+ });
102
+ });