@applicaster/zapp-react-native-utils 15.0.0-rc.127 → 15.0.0-rc.128
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/manifestUtils/_internals/__tests__/index.test.js +41 -0
- package/manifestUtils/_internals/index.js +33 -0
- package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +49 -0
- package/manifestUtils/fieldUtils/index.js +54 -0
- package/manifestUtils/index.js +2 -0
- package/manifestUtils/keys.js +228 -0
- package/manifestUtils/mobileAction/button/__tests__/mobileActionButton.test.js +168 -0
- package/manifestUtils/mobileAction/button/index.js +140 -0
- package/manifestUtils/mobileAction/container/__tests__/mobileActionButtonsContainer.test.js +102 -0
- package/manifestUtils/mobileAction/container/index.js +73 -0
- package/manifestUtils/mobileAction/groups/__tests__/buildMobileActionButtonGroups.test.js +127 -0
- package/manifestUtils/mobileAction/groups/defaults.js +75 -0
- package/manifestUtils/mobileAction/groups/index.js +80 -0
- package/package.json +2 -2
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const {
|
|
2
|
+
isKeyHasSuffix,
|
|
3
|
+
isKeyHasAnyOfSuffixes,
|
|
4
|
+
getKeyWithPrefixGenerator,
|
|
5
|
+
} = require("..");
|
|
6
|
+
|
|
7
|
+
describe("manifestUtils/_internals helpers", () => {
|
|
8
|
+
it("checks a key suffix", () => {
|
|
9
|
+
expect(
|
|
10
|
+
isKeyHasSuffix("button_enabled", "mobile_button_1_button_enabled")
|
|
11
|
+
).toBe(true);
|
|
12
|
+
|
|
13
|
+
expect(
|
|
14
|
+
isKeyHasSuffix("button_enabled", "mobile_button_1_assign_action")
|
|
15
|
+
).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("checks key against multiple suffixes", () => {
|
|
19
|
+
const suffixes = ["font_color", "focused_font_color", "text_transform"];
|
|
20
|
+
|
|
21
|
+
expect(
|
|
22
|
+
isKeyHasAnyOfSuffixes(suffixes, "mobile_button_1_text_transform")
|
|
23
|
+
).toBe(true);
|
|
24
|
+
|
|
25
|
+
expect(
|
|
26
|
+
isKeyHasAnyOfSuffixes(suffixes, "mobile_button_1_asset_alignment")
|
|
27
|
+
).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("generates stable key names using a prefix", () => {
|
|
31
|
+
const withMobileButtonPrefix = getKeyWithPrefixGenerator("mobile_button_2");
|
|
32
|
+
|
|
33
|
+
expect(withMobileButtonPrefix("display_mode")).toBe(
|
|
34
|
+
"mobile_button_2_display_mode"
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
expect(withMobileButtonPrefix("asset_enabled")).toBe(
|
|
38
|
+
"mobile_button_2_asset_enabled"
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -174,6 +174,36 @@ function generateFieldsFromDefaultsWithoutPrefixedLabel(
|
|
|
174
174
|
)(fields);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Checks whether a generated manifest field key ends with the given suffix.
|
|
179
|
+
*
|
|
180
|
+
* @param {string} suffix
|
|
181
|
+
* @param {string} key
|
|
182
|
+
* @returns {boolean}
|
|
183
|
+
*/
|
|
184
|
+
const isKeyHasSuffix = (suffix, key) => key.endsWith(`_${suffix}`);
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Checks whether a generated manifest field key ends with any supported suffix.
|
|
188
|
+
*
|
|
189
|
+
* @param {string[]} suffixes
|
|
190
|
+
* @param {string} key
|
|
191
|
+
* @returns {boolean}
|
|
192
|
+
*/
|
|
193
|
+
const isKeyHasAnyOfSuffixes = (suffixes, key) =>
|
|
194
|
+
suffixes.some((suffix) => key.endsWith(`_${suffix}`));
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Creates a helper that prefixes a manifest field suffix with a shared key stem.
|
|
198
|
+
*
|
|
199
|
+
* @param {string} prefix
|
|
200
|
+
* @returns {(suffix: string) => string}
|
|
201
|
+
*/
|
|
202
|
+
function getKeyWithPrefixGenerator(prefix) {
|
|
203
|
+
// expect prefix as lower snake case, e.g. "mobile_buttons_container"
|
|
204
|
+
return (suffix) => `${prefix}_${suffix}`;
|
|
205
|
+
}
|
|
206
|
+
|
|
177
207
|
module.exports = {
|
|
178
208
|
toSnakeCase,
|
|
179
209
|
toCamelCase,
|
|
@@ -185,4 +215,7 @@ module.exports = {
|
|
|
185
215
|
getDefaultConfiguration,
|
|
186
216
|
compact,
|
|
187
217
|
replaceUnderscoreToSpace,
|
|
218
|
+
isKeyHasSuffix,
|
|
219
|
+
isKeyHasAnyOfSuffixes,
|
|
220
|
+
getKeyWithPrefixGenerator,
|
|
188
221
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const {
|
|
2
|
+
withConditional,
|
|
3
|
+
getConditionalKey,
|
|
4
|
+
createConditionalField,
|
|
5
|
+
} = require("..");
|
|
6
|
+
|
|
7
|
+
describe("manifestUtils/fieldUtils", () => {
|
|
8
|
+
it("appends conditions and adds all_conditions when there is more than one condition", () => {
|
|
9
|
+
const config = {
|
|
10
|
+
key: "mobile_button_1_width",
|
|
11
|
+
conditional_fields: [
|
|
12
|
+
{ key: "styles/mobile_button_1_button_enabled", condition_value: true },
|
|
13
|
+
],
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const result = withConditional([
|
|
17
|
+
{ key: "styles/mobile_button_1_display_mode", condition_value: "fixed" },
|
|
18
|
+
])(config);
|
|
19
|
+
|
|
20
|
+
expect(result.conditional_fields).toEqual([
|
|
21
|
+
{ key: "styles/mobile_button_1_button_enabled", condition_value: true },
|
|
22
|
+
{ key: "styles/mobile_button_1_display_mode", condition_value: "fixed" },
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
expect(result.rules).toBe("all_conditions");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("creates category-prefixed conditional key", () => {
|
|
29
|
+
expect(
|
|
30
|
+
getConditionalKey("mobile_buttons_container_position", "styles")
|
|
31
|
+
).toBe("styles/mobile_buttons_container_position");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("creates conditional fields with default category and with raw key", () => {
|
|
35
|
+
expect(
|
|
36
|
+
createConditionalField("mobile_button_1_asset_enabled", true)
|
|
37
|
+
).toEqual({
|
|
38
|
+
key: "styles/mobile_button_1_asset_enabled",
|
|
39
|
+
condition_value: true,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
expect(
|
|
43
|
+
createConditionalField("mobile_button_1_asset_enabled", true, null)
|
|
44
|
+
).toEqual({
|
|
45
|
+
key: "mobile_button_1_asset_enabled",
|
|
46
|
+
condition_value: true,
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Appends new conditional_fields from conditions array
|
|
3
|
+
* to config.conditional_fields
|
|
4
|
+
* if there are more than 1 condition, sets rules to "all_conditions"
|
|
5
|
+
*
|
|
6
|
+
* @param {Array<{key: string, condition_value: unknown}>} conditions
|
|
7
|
+
* @returns {(config: object) => object}
|
|
8
|
+
*/
|
|
9
|
+
const withConditional = (conditions) => (config) => {
|
|
10
|
+
const conditional_fields = [
|
|
11
|
+
...(config.conditional_fields || []),
|
|
12
|
+
...conditions,
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const next = { ...config, conditional_fields };
|
|
16
|
+
|
|
17
|
+
if (conditional_fields.length > 1) {
|
|
18
|
+
return { ...next, rules: "all_conditions" };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return next;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Builds key for conditional fields prepending category, e.g. "styles/mobile_buttons_container_position"
|
|
26
|
+
*
|
|
27
|
+
* @param {string} key
|
|
28
|
+
* @param {string} category
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
function getConditionalKey(key, category) {
|
|
32
|
+
return `${category}/${key}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Returns a conditional field object for manifest visibility rules.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} key
|
|
39
|
+
* @param {unknown} condition_value
|
|
40
|
+
* @param {string|null} [category="styles"] Pass `null` to use the key as-is.
|
|
41
|
+
* @returns {{key: string, condition_value: unknown}}
|
|
42
|
+
*/
|
|
43
|
+
function createConditionalField(key, condition_value, category = "styles") {
|
|
44
|
+
return {
|
|
45
|
+
key: category ? getConditionalKey(key, category) : key,
|
|
46
|
+
condition_value,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
withConditional,
|
|
52
|
+
getConditionalKey,
|
|
53
|
+
createConditionalField,
|
|
54
|
+
};
|
package/manifestUtils/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
|
|
9
9
|
const { tvActionButtonsContainer } = require("./tvAction/container");
|
|
10
10
|
const { tvActionButton } = require("./tvAction/button");
|
|
11
|
+
const { buildMobileActionButtonGroups } = require("./mobileAction/groups");
|
|
11
12
|
const { compact } = require("./_internals");
|
|
12
13
|
|
|
13
14
|
const { spacingKey, absolutePositionElement } = require("./containers");
|
|
@@ -43,6 +44,7 @@ module.exports = {
|
|
|
43
44
|
tvMenuLabel,
|
|
44
45
|
tvActionButtonsContainer,
|
|
45
46
|
tvActionButton,
|
|
47
|
+
buildMobileActionButtonGroups,
|
|
46
48
|
mobileCellLabel,
|
|
47
49
|
tvCellLabel,
|
|
48
50
|
tvBadges,
|
package/manifestUtils/keys.js
CHANGED
|
@@ -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: "more" },
|
|
477
|
+
{ text: "add to calendar", value: "add_to_calendar" },
|
|
478
|
+
{ text: "share", value: "share" },
|
|
479
|
+
{ text: "downloads", value: "downloads" },
|
|
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 flavor",
|
|
545
|
+
options: ["flavor_1", "flavor_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
|
+
actionAssetFlavor: "flavor_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 actionAssetFlavorField = result.fields.find(
|
|
103
|
+
(field) => field.key === "mobile_button_2_action_asset_flavor"
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(actionAssetFlavorField.rules).toBe("all_conditions");
|
|
107
|
+
|
|
108
|
+
expect(actionAssetFlavorField.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_flavor",
|
|
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
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const { mobileActionButtonContainerFields } = require("../../keys");
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
isKeyHasSuffix,
|
|
5
|
+
toSnakeCase,
|
|
6
|
+
generateFieldsFromDefaultsWithoutPrefixedLabel,
|
|
7
|
+
getKeyWithPrefixGenerator,
|
|
8
|
+
} = require("../../_internals");
|
|
9
|
+
|
|
10
|
+
const { withConditional, createConditionalField } = require("../../fieldUtils");
|
|
11
|
+
|
|
12
|
+
const { fieldsGroup } = require("../../utils");
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Builds the manifest group for the mobile action buttons container and wires
|
|
16
|
+
* child field visibility to the container-level toggles and layout selections.
|
|
17
|
+
*
|
|
18
|
+
* @param {object} options
|
|
19
|
+
* @param {string} options.label
|
|
20
|
+
* @param {string} options.description
|
|
21
|
+
* @param {object} options.defaults
|
|
22
|
+
* @returns {object}
|
|
23
|
+
*/
|
|
24
|
+
function mobileActionButtonsContainer({ label, description, defaults }) {
|
|
25
|
+
const containerKeyFromLabel = toSnakeCase(label); // "Mobile Buttons Container" -> "mobile_buttons_container"
|
|
26
|
+
|
|
27
|
+
const generatedFields = generateFieldsFromDefaultsWithoutPrefixedLabel(
|
|
28
|
+
label,
|
|
29
|
+
defaults,
|
|
30
|
+
mobileActionButtonContainerFields(defaults.position)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const keyPrefixGenerator = getKeyWithPrefixGenerator(containerKeyFromLabel);
|
|
34
|
+
|
|
35
|
+
const enabledKey = keyPrefixGenerator("buttons_enabled");
|
|
36
|
+
const positionKey = keyPrefixGenerator("position");
|
|
37
|
+
const stackingKey = keyPrefixGenerator("stacking");
|
|
38
|
+
|
|
39
|
+
const defaultConditions = [createConditionalField(enabledKey, true)];
|
|
40
|
+
|
|
41
|
+
const fields = generatedFields.map((field) => {
|
|
42
|
+
const key = field.key;
|
|
43
|
+
|
|
44
|
+
if (isKeyHasSuffix("buttons_enabled", key)) {
|
|
45
|
+
return field;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const conditions = [...defaultConditions];
|
|
49
|
+
|
|
50
|
+
// over_image_position depends on [positionKey: over_image]
|
|
51
|
+
if (isKeyHasSuffix("over_image_position", key)) {
|
|
52
|
+
conditions.push(createConditionalField(positionKey, "over_image"));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// horizontal_gutter depends on [stackingKey: horizontal]
|
|
56
|
+
if (isKeyHasSuffix("horizontal_gutter", key)) {
|
|
57
|
+
conditions.push(createConditionalField(stackingKey, "horizontal"));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// vertical_gutter depends on [stackingKey: vertical]
|
|
61
|
+
if (isKeyHasSuffix("vertical_gutter", key)) {
|
|
62
|
+
conditions.push(createConditionalField(stackingKey, "vertical"));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return withConditional(conditions)(field);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return fieldsGroup(label, description, fields);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
mobileActionButtonsContainer,
|
|
73
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { buildMobileActionButtonGroups } from "..";
|
|
2
|
+
|
|
3
|
+
describe("buildMobileActionButtonGroups", () => {
|
|
4
|
+
it("builds the container and three button groups with shared defaults", () => {
|
|
5
|
+
const groups = buildMobileActionButtonGroups({
|
|
6
|
+
containerDefaults: {
|
|
7
|
+
position: ["over_image", "text_label_1", "text_label_2"],
|
|
8
|
+
},
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
expect(groups).toHaveLength(4);
|
|
12
|
+
|
|
13
|
+
expect(groups.map((group) => group.label)).toEqual([
|
|
14
|
+
"Mobile Buttons Container",
|
|
15
|
+
"Mobile Button 1",
|
|
16
|
+
"Mobile Button 2",
|
|
17
|
+
"Mobile Button 3",
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const containerFields = groups[0].fields;
|
|
21
|
+
|
|
22
|
+
const positionField = containerFields.find(
|
|
23
|
+
(field) => field.key === "mobile_buttons_container_position"
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const buttonsEnabledField = containerFields.find(
|
|
27
|
+
(field) => field.key === "mobile_buttons_container_buttons_enabled"
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
expect(positionField.options).toEqual([
|
|
31
|
+
"over_image",
|
|
32
|
+
"text_label_1",
|
|
33
|
+
"text_label_2",
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
expect(buttonsEnabledField.initial_value).toBe(false);
|
|
37
|
+
|
|
38
|
+
const button1Fields = groups[1].fields;
|
|
39
|
+
|
|
40
|
+
const button1EnabledField = button1Fields.find(
|
|
41
|
+
(field) => field.key === "mobile_button_1_button_enabled"
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const button1AssignActionField = button1Fields.find(
|
|
45
|
+
(field) => field.key === "mobile_button_1_assign_action"
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const button1BackgroundColorField = button1Fields.find(
|
|
49
|
+
(field) => field.key === "mobile_button_1_background_color"
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
expect(button1EnabledField.initial_value).toBe(true);
|
|
53
|
+
expect(button1AssignActionField.initial_value).toBe("navigation_action");
|
|
54
|
+
|
|
55
|
+
expect(button1BackgroundColorField.initial_value).toBe(
|
|
56
|
+
"rgba(254, 20, 72, 1)"
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const button2Fields = groups[2].fields;
|
|
60
|
+
|
|
61
|
+
const button2EnabledField = button2Fields.find(
|
|
62
|
+
(field) => field.key === "mobile_button_2_button_enabled"
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const button2AssignActionField = button2Fields.find(
|
|
66
|
+
(field) => field.key === "mobile_button_2_assign_action"
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
expect(button2EnabledField.initial_value).toBe(false);
|
|
70
|
+
expect(button2AssignActionField.initial_value).toBe("secondary_navigation");
|
|
71
|
+
|
|
72
|
+
const button3Fields = groups[3].fields;
|
|
73
|
+
|
|
74
|
+
const button3EnabledField = button3Fields.find(
|
|
75
|
+
(field) => field.key === "mobile_button_3_button_enabled"
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const button3AssignActionField = button3Fields.find(
|
|
79
|
+
(field) => field.key === "mobile_button_3_assign_action"
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
expect(button3EnabledField.initial_value).toBe(false);
|
|
83
|
+
|
|
84
|
+
expect(button3AssignActionField.initial_value).toBe(
|
|
85
|
+
"local_storage_favourites_action"
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("merges container, shared button, and per-button overrides", () => {
|
|
90
|
+
const groups = buildMobileActionButtonGroups({
|
|
91
|
+
containerDefaults: {
|
|
92
|
+
align: "center",
|
|
93
|
+
position: ["over_image"],
|
|
94
|
+
},
|
|
95
|
+
sharedButtonDefaults: {
|
|
96
|
+
assetAlignment: "right",
|
|
97
|
+
},
|
|
98
|
+
buttonOverrides: {
|
|
99
|
+
2: {
|
|
100
|
+
buttonEnabled: true,
|
|
101
|
+
assignAction: "downloads",
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const alignField = groups[0].fields.find(
|
|
107
|
+
(field) => field.key === "mobile_buttons_container_align"
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const button1AssetAlignmentField = groups[1].fields.find(
|
|
111
|
+
(field) => field.key === "mobile_button_1_asset_alignment"
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const button2EnabledField = groups[2].fields.find(
|
|
115
|
+
(field) => field.key === "mobile_button_2_button_enabled"
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const button2AssignActionField = groups[2].fields.find(
|
|
119
|
+
(field) => field.key === "mobile_button_2_assign_action"
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
expect(alignField.initial_value).toBe("center");
|
|
123
|
+
expect(button1AssetAlignmentField.initial_value).toBe("right");
|
|
124
|
+
expect(button2EnabledField.initial_value).toBe(true);
|
|
125
|
+
expect(button2AssignActionField.initial_value).toBe("downloads");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const DEFAULT_MOBILE_ACTION_BUTTONS_CONTAINER_DEFAULTS = {
|
|
2
|
+
buttonsEnabled: false,
|
|
3
|
+
align: "left",
|
|
4
|
+
overImagePosition: "bottom_left",
|
|
5
|
+
marginTop: 0,
|
|
6
|
+
marginRight: 20,
|
|
7
|
+
marginBottom: 0,
|
|
8
|
+
marginLeft: 20,
|
|
9
|
+
stacking: "horizontal",
|
|
10
|
+
horizontalGutter: 8,
|
|
11
|
+
verticalGutter: 8,
|
|
12
|
+
independentStyles: true,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const DEFAULT_MOBILE_ACTION_BUTTON_SHARED_DEFAULTS = {
|
|
16
|
+
displayMode: "dynamic",
|
|
17
|
+
width: 140,
|
|
18
|
+
contentsAlignment: "center",
|
|
19
|
+
backgroundColor: "rgba(62, 62, 62, 1)",
|
|
20
|
+
focusedBackgroundColor: "rgba(46, 46, 46, 1)",
|
|
21
|
+
borderColor: "rgba(0, 0, 0, 0)",
|
|
22
|
+
focusedBorderColor: "rgba(0, 0, 0, 0)",
|
|
23
|
+
borderSize: 0,
|
|
24
|
+
cornerRadius: 8,
|
|
25
|
+
paddingTop: 14,
|
|
26
|
+
paddingRight: 24,
|
|
27
|
+
paddingBottom: 14,
|
|
28
|
+
paddingLeft: 16,
|
|
29
|
+
assetEnabled: true,
|
|
30
|
+
actionAssetFlavor: "flavor_1",
|
|
31
|
+
assetAlignment: "left",
|
|
32
|
+
assetHeight: 24,
|
|
33
|
+
assetWidth: 24,
|
|
34
|
+
assetMarginTop: 0,
|
|
35
|
+
assetMarginRight: 6,
|
|
36
|
+
assetMarginBottom: 0,
|
|
37
|
+
assetMarginLeft: 0,
|
|
38
|
+
labelEnabled: true,
|
|
39
|
+
fontColor: "rgba(239, 239, 239, 1)",
|
|
40
|
+
focusedFontColor: "rgba(239, 239, 239, 1)",
|
|
41
|
+
iosFontFamily: "Ubuntu-Bold",
|
|
42
|
+
androidFontFamily: "Ubuntu-Bold",
|
|
43
|
+
fontSize: 15,
|
|
44
|
+
lineHeight: 24,
|
|
45
|
+
iosLetterSpacing: -0.2,
|
|
46
|
+
androidLetterSpacing: -0.2,
|
|
47
|
+
textTransform: "default",
|
|
48
|
+
marginTop: 0,
|
|
49
|
+
marginRight: 0,
|
|
50
|
+
marginBottom: 0,
|
|
51
|
+
marginLeft: 0,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const DEFAULT_MOBILE_ACTION_BUTTON_PRESETS = {
|
|
55
|
+
1: {
|
|
56
|
+
buttonEnabled: true,
|
|
57
|
+
assignAction: "navigation_action",
|
|
58
|
+
backgroundColor: "rgba(254, 20, 72, 1)",
|
|
59
|
+
focusedBackgroundColor: "rgba(213, 8, 54, 1)",
|
|
60
|
+
},
|
|
61
|
+
2: {
|
|
62
|
+
buttonEnabled: false,
|
|
63
|
+
assignAction: "secondary_navigation",
|
|
64
|
+
},
|
|
65
|
+
3: {
|
|
66
|
+
buttonEnabled: false,
|
|
67
|
+
assignAction: "local_storage_favourites_action",
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
DEFAULT_MOBILE_ACTION_BUTTONS_CONTAINER_DEFAULTS,
|
|
73
|
+
DEFAULT_MOBILE_ACTION_BUTTON_SHARED_DEFAULTS,
|
|
74
|
+
DEFAULT_MOBILE_ACTION_BUTTON_PRESETS,
|
|
75
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const { mobileActionButtonsContainer } = require("../container");
|
|
2
|
+
const { mobileActionButton } = require("../button");
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
DEFAULT_MOBILE_ACTION_BUTTONS_CONTAINER_DEFAULTS,
|
|
6
|
+
DEFAULT_MOBILE_ACTION_BUTTON_SHARED_DEFAULTS,
|
|
7
|
+
DEFAULT_MOBILE_ACTION_BUTTON_PRESETS,
|
|
8
|
+
} = require("./defaults");
|
|
9
|
+
|
|
10
|
+
const CONTAINER_GROUP_LABEL = "Mobile Buttons Container"; // NOTE: used as key – "Mobile Buttons Container" -> "mobile_buttons_container"
|
|
11
|
+
|
|
12
|
+
const CONTAINER_GROUP_DESCRIPTION =
|
|
13
|
+
"Configuration for mobile action buttons container";
|
|
14
|
+
|
|
15
|
+
const BUTTON_GROUPS = [
|
|
16
|
+
{
|
|
17
|
+
index: 1,
|
|
18
|
+
label: "Mobile Button 1",
|
|
19
|
+
description: "Primary mobile action button",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
index: 2,
|
|
23
|
+
label: "Mobile Button 2",
|
|
24
|
+
description: "Secondary mobile action button",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
index: 3,
|
|
28
|
+
label: "Mobile Button 3",
|
|
29
|
+
description: "Tertiary mobile action button",
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Builds the shared mobile action button manifest groups while letting each
|
|
35
|
+
* plugin supply only its supported insertion positions and explicit overrides.
|
|
36
|
+
*
|
|
37
|
+
* @param {object} options
|
|
38
|
+
* @param {object} [options.containerDefaults={}]
|
|
39
|
+
* @param {object} [options.sharedButtonDefaults={}]
|
|
40
|
+
* @param {Record<number, object>} [options.buttonOverrides={}]
|
|
41
|
+
* @returns {object[]}
|
|
42
|
+
*/
|
|
43
|
+
function buildMobileActionButtonGroups({
|
|
44
|
+
containerDefaults = {},
|
|
45
|
+
sharedButtonDefaults = {},
|
|
46
|
+
buttonOverrides = {},
|
|
47
|
+
}) {
|
|
48
|
+
const groups = [
|
|
49
|
+
mobileActionButtonsContainer({
|
|
50
|
+
label: CONTAINER_GROUP_LABEL,
|
|
51
|
+
description: CONTAINER_GROUP_DESCRIPTION,
|
|
52
|
+
defaults: {
|
|
53
|
+
...DEFAULT_MOBILE_ACTION_BUTTONS_CONTAINER_DEFAULTS,
|
|
54
|
+
...containerDefaults,
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
BUTTON_GROUPS.forEach(({ index, label, description }) => {
|
|
60
|
+
groups.push(
|
|
61
|
+
mobileActionButton({
|
|
62
|
+
isFirstButton: index === 1,
|
|
63
|
+
label,
|
|
64
|
+
description,
|
|
65
|
+
defaults: {
|
|
66
|
+
...DEFAULT_MOBILE_ACTION_BUTTON_SHARED_DEFAULTS,
|
|
67
|
+
...sharedButtonDefaults,
|
|
68
|
+
...DEFAULT_MOBILE_ACTION_BUTTON_PRESETS[index],
|
|
69
|
+
...(buttonOverrides[index] || {}),
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return groups;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
buildMobileActionButtonGroups,
|
|
80
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "15.0.0-rc.
|
|
3
|
+
"version": "15.0.0-rc.128",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "15.0.0-rc.
|
|
30
|
+
"@applicaster/applicaster-types": "15.0.0-rc.128",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|