@applicaster/zapp-react-native-ui-components 16.0.0-alpha.1593888345 → 16.0.0-alpha.1701179921

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 (48) hide show
  1. package/Components/LinkHandler/LinkHandler.tsx +2 -7
  2. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
  3. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
  4. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
  5. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +2 -4
  6. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -3
  7. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
  8. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -2
  9. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +4 -2
  10. package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
  11. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +5 -2
  12. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +4 -1
  13. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +58 -73
  14. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +65 -56
  15. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +140 -65
  16. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +93 -46
  17. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +148 -32
  18. package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +113 -0
  19. package/Components/ModalComponent/AudioPlayer/Components/__tests__/NowPlayingHeaderSection.test.tsx +36 -0
  20. package/Components/ModalComponent/AudioPlayer/Components/index.ts +0 -2
  21. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +132 -6
  22. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +202 -13
  23. package/Components/ModalComponent/BottomSheetModalContent.tsx +187 -73
  24. package/Components/ModalComponent/SortableList.tsx +36 -22
  25. package/Components/ModalComponent/TextInputContent.tsx +42 -7
  26. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +111 -6
  27. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +50 -1
  28. package/Components/ModalComponent/index.tsx +7 -9
  29. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +24 -0
  30. package/Components/ModalComponent/presets/selectableCell.tsx +1 -1
  31. package/Components/ModalComponent/showTextInput.ts +11 -2
  32. package/Components/PlayerContainer/PlayerContainer.tsx +8 -1
  33. package/Components/River/ComponentsMap/ComponentsMap.tsx +10 -12
  34. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +138 -75
  35. package/Components/River/__tests__/componentsMap.test.js +8 -3
  36. package/Components/Screen/__tests__/Screen.test.tsx +24 -0
  37. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
  38. package/Components/Screen/index.tsx +5 -0
  39. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +1 -1
  40. package/Components/Transitioner/Transitioner.tsx +2 -3
  41. package/Components/Transitioner/__tests__/transitioner.test.js +83 -2
  42. package/Components/VideoLive/LiveImageManager.ts +8 -2
  43. package/Components/VideoLive/__tests__/LiveImageManager.test.ts +59 -0
  44. package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
  45. package/Contexts/ModalNavigationContext/index.tsx +2 -2
  46. package/assets/empty-Info.png +0 -0
  47. package/package.json +5 -5
  48. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +0 -314
@@ -1,11 +1,10 @@
1
1
  /**
2
2
  * Modal Building Block — Header
3
3
  *
4
- * Single-file Expo Snack demo for the Header building block spec.
5
- *
6
4
  * Green (configurable): title, closeButton (enable + asset), actionButtons styling
7
- * White (hardcoded): container, action button layout/enable/actions, close dimensions,
8
- * action button padding/radius, action labels
5
+ * (incl. Clear padding/radius for Variant 3 / section_header Studio keys)
6
+ * White (hardcoded): container gutters, action button slot enablement/actions,
7
+ * close dimensions, default action labels (overridable via HeaderData.clearLabel)
9
8
  */
10
9
 
11
10
  import React, { useCallback, useState } from "react";
@@ -63,11 +62,7 @@ export type TextTransform =
63
62
  export type TitleAlignment = "left" | "center";
64
63
 
65
64
  /** Selects hardcoded container + action layout (white fields). */
66
- export type HeaderVariant =
67
- | "singleLine"
68
- | "headerWithActions"
69
- | "headerWithActionsCancelOnly"
70
- | "section";
65
+ export type HeaderVariant = "singleLine" | "headerWithActions" | "section";
71
66
 
72
67
  export type TitleConfiguration = {
73
68
  fontColor: string;
@@ -98,6 +93,12 @@ export type ActionButtonsStyleConfiguration = {
98
93
  iosLetterSpacing: number;
99
94
  androidLetterSpacing: number;
100
95
  textTransform: TextTransform;
96
+ /** Green Variant 3 fields — defaults match ACTION_BUTTON_LAYOUT_SPEC. */
97
+ paddingTop?: number;
98
+ paddingRight?: number;
99
+ paddingBottom?: number;
100
+ paddingLeft?: number;
101
+ cornerRadius?: number;
101
102
  };
102
103
 
103
104
  export type HeaderConfiguration = {
@@ -137,6 +138,11 @@ export const DEFAULT_ACTION_BUTTONS_STYLE_CONFIGURATION: ActionButtonsStyleConfi
137
138
  iosLetterSpacing: 0,
138
139
  androidLetterSpacing: 0,
139
140
  textTransform: "default",
141
+ paddingTop: 6,
142
+ paddingRight: 10,
143
+ paddingBottom: 6,
144
+ paddingLeft: 10,
145
+ cornerRadius: 16,
140
146
  };
141
147
 
142
148
  // ---------------------------------------------------------------------------
@@ -145,6 +151,8 @@ export const DEFAULT_ACTION_BUTTONS_STYLE_CONFIGURATION: ActionButtonsStyleConfi
145
151
 
146
152
  export type HeaderData = {
147
153
  title: string;
154
+ /** Localization override for Clear; falls back to ACTION_LABELS.clear. */
155
+ clearLabel?: string;
148
156
  };
149
157
 
150
158
  export type AudioPlayerHeaderProps = {
@@ -198,13 +206,6 @@ const CONTAINER_SPEC: Record<HeaderVariant, ContainerSpec> = {
198
206
  paddingBottom: 8,
199
207
  paddingLeft: 20,
200
208
  },
201
- headerWithActionsCancelOnly: {
202
- horizontalGutter: 12,
203
- paddingTop: 0,
204
- paddingRight: 20,
205
- paddingBottom: 8,
206
- paddingLeft: 20,
207
- },
208
209
  section: {
209
210
  horizontalGutter: 12,
210
211
  paddingTop: 0,
@@ -228,11 +229,6 @@ const ACTION_BUTTONS_BEHAVIOR: Record<
228
229
  leading: { enabled: true, actionType: "cancel" },
229
230
  trailing: { enabled: true, actionType: "done" },
230
231
  },
231
- headerWithActionsCancelOnly: {
232
- sectionEnabled: true,
233
- leading: { enabled: true, actionType: "cancel" },
234
- trailing: { enabled: false },
235
- },
236
232
  section: {
237
233
  sectionEnabled: true,
238
234
  leading: { enabled: false },
@@ -453,6 +449,7 @@ type HeaderActionButtonProps = {
453
449
  actionType: HeaderActionType;
454
450
  configuration: ActionButtonsStyleConfiguration;
455
451
  focused?: boolean;
452
+ label?: string;
456
453
  onPress?: () => void;
457
454
  };
458
455
 
@@ -460,8 +457,24 @@ function HeaderActionButton({
460
457
  actionType,
461
458
  configuration,
462
459
  focused = false,
460
+ label,
463
461
  onPress,
464
462
  }: HeaderActionButtonProps) {
463
+ const paddingTop =
464
+ configuration.paddingTop ?? ACTION_BUTTON_LAYOUT_SPEC.paddingTop;
465
+
466
+ const paddingRight =
467
+ configuration.paddingRight ?? ACTION_BUTTON_LAYOUT_SPEC.paddingRight;
468
+
469
+ const paddingBottom =
470
+ configuration.paddingBottom ?? ACTION_BUTTON_LAYOUT_SPEC.paddingBottom;
471
+
472
+ const paddingLeft =
473
+ configuration.paddingLeft ?? ACTION_BUTTON_LAYOUT_SPEC.paddingLeft;
474
+
475
+ const cornerRadius =
476
+ configuration.cornerRadius ?? ACTION_BUTTON_LAYOUT_SPEC.cornerRadius;
477
+
465
478
  return (
466
479
  <Pressable
467
480
  onPress={onPress}
@@ -470,11 +483,11 @@ function HeaderActionButton({
470
483
  pressed || focused
471
484
  ? configuration.focusedBackgroundColor
472
485
  : configuration.defaultBackgroundColor,
473
- borderRadius: ACTION_BUTTON_LAYOUT_SPEC.cornerRadius,
474
- paddingTop: ACTION_BUTTON_LAYOUT_SPEC.paddingTop,
475
- paddingRight: ACTION_BUTTON_LAYOUT_SPEC.paddingRight,
476
- paddingBottom: ACTION_BUTTON_LAYOUT_SPEC.paddingBottom,
477
- paddingLeft: ACTION_BUTTON_LAYOUT_SPEC.paddingLeft,
486
+ borderRadius: cornerRadius,
487
+ paddingTop,
488
+ paddingRight,
489
+ paddingBottom,
490
+ paddingLeft,
478
491
  })}
479
492
  >
480
493
  <Text
@@ -497,7 +510,7 @@ function HeaderActionButton({
497
510
  }}
498
511
  numberOfLines={1}
499
512
  >
500
- {ACTION_LABELS[actionType]}
513
+ {label || ACTION_LABELS[actionType]}
501
514
  </Text>
502
515
  </Pressable>
503
516
  );
@@ -610,14 +623,20 @@ export function AudioPlayerHeader({
610
623
  onClear,
611
624
  }: AudioPlayerHeaderProps) {
612
625
  const modalBlocksStyle = useModalBlocksStyle();
613
- const headerBlock = modalBlocksStyle?.header;
626
+
627
+ // Next Up section header uses sectionHeader — never Theme modal `header`,
628
+ // so the Queue title styles do not collide with the section title.
629
+ const styleBlock =
630
+ configuration.variant === "section"
631
+ ? modalBlocksStyle?.sectionHeader
632
+ : modalBlocksStyle?.header;
614
633
 
615
634
  const effectiveConfig = React.useMemo(() => {
616
- return mergeHeaderConfiguration(configuration, headerBlock);
617
- }, [configuration, headerBlock]);
635
+ return mergeHeaderConfiguration(configuration, styleBlock);
636
+ }, [configuration, styleBlock]);
618
637
 
619
638
  const { variant, title, closeButton, actionButtons } = effectiveConfig;
620
- const { title: titleText } = data;
639
+ const { title: titleText, clearLabel } = data;
621
640
 
622
641
  const container = CONTAINER_SPEC[variant];
623
642
  const behavior = ACTION_BUTTONS_BEHAVIOR[variant];
@@ -628,16 +647,24 @@ export function AudioPlayerHeader({
628
647
  behavior.sectionEnabled
629
648
  );
630
649
 
631
- const showTrailingAction = shouldShowActionSlot(
632
- behavior.trailing,
633
- behavior.sectionEnabled
634
- );
650
+ const showTrailingAction =
651
+ shouldShowActionSlot(behavior.trailing, behavior.sectionEnabled) &&
652
+ (behavior.trailing.actionType !== "clear" || !!onClear);
653
+
654
+ const actionLabelFor = (actionType?: HeaderActionType) => {
655
+ if (actionType === "clear" && clearLabel) {
656
+ return clearLabel;
657
+ }
658
+
659
+ return actionType ? ACTION_LABELS[actionType] : undefined;
660
+ };
635
661
 
636
662
  const leadingContent = showLeadingAction ? (
637
663
  <HeaderActionButton
638
- actionType={behavior.leading.actionType}
664
+ actionType={behavior.leading.actionType as HeaderActionType}
639
665
  configuration={actionButtons}
640
666
  focused={focusedLeadingAction}
667
+ label={actionLabelFor(behavior.leading.actionType)}
641
668
  onPress={onCancel}
642
669
  />
643
670
  ) : onBack ? (
@@ -646,9 +673,10 @@ export function AudioPlayerHeader({
646
673
 
647
674
  const trailingContent = showTrailingAction ? (
648
675
  <HeaderActionButton
649
- actionType={behavior.trailing.actionType}
676
+ actionType={behavior.trailing.actionType as HeaderActionType}
650
677
  configuration={actionButtons}
651
678
  focused={focusedTrailingAction}
679
+ label={actionLabelFor(behavior.trailing.actionType)}
652
680
  onPress={behavior.trailing.actionType === "done" ? onDone : onClear}
653
681
  />
654
682
  ) : closeButton.enabled && !isCenterAligned ? (
@@ -725,25 +753,6 @@ export const VARIANT_HEADER_WITH_ACTIONS: HeaderConfiguration = {
725
753
  paddingTop: 16,
726
754
  };
727
755
 
728
- /** Variant 2 — single side action (layout rule demo) */
729
- export const VARIANT_HEADER_WITH_CANCEL_ONLY: HeaderConfiguration = {
730
- variant: "headerWithActionsCancelOnly",
731
- title: {
732
- fontColor: "#FFFFFF",
733
- iosFontFamily: "SFProText-Bold",
734
- androidFontFamily: "Roboto-Bold",
735
- fontSize: 22,
736
- lineHeight: 28,
737
- iosLetterSpacing: -0.6,
738
- androidLetterSpacing: 0,
739
- textTransform: "default",
740
- alignment: "center",
741
- },
742
- closeButton: { enabled: false },
743
- actionButtons: DEFAULT_ACTION_BUTTONS_STYLE_CONFIGURATION,
744
- paddingTop: 16,
745
- };
746
-
747
756
  /** Variant 3 — Section Header */
748
757
  export const VARIANT_SECTION_HEADER: HeaderConfiguration = {
749
758
  variant: "section",
@@ -18,11 +18,42 @@ import {
18
18
  View,
19
19
  } from "react-native";
20
20
 
21
+ import { resolveDefaultAssetUri } from "@applicaster/zapp-react-native-utils/actionUtils";
22
+
21
23
  const styles = StyleSheet.create({
22
24
  column: {
23
25
  alignItems: "center",
24
26
  width: "100%",
25
27
  },
28
+ validationMessage: {
29
+ flexDirection: "row",
30
+ alignItems: "center",
31
+ alignSelf: "center",
32
+ overflow: "hidden",
33
+ backgroundColor: "rgba(229,30,37,1.00)",
34
+ borderRadius: 100,
35
+ marginTop: 16,
36
+ paddingLeft: 8,
37
+ paddingRight: 12,
38
+ paddingTop: 8,
39
+ paddingBottom: 8,
40
+ gap: 8,
41
+ },
42
+ validationMessageIcon: {
43
+ width: 20,
44
+ height: 20,
45
+ alignSelf: "flex-start",
46
+ },
47
+ validationMessageText: {
48
+ color: "rgba(255,255,255,1.00)",
49
+ fontFamily: Platform.select({
50
+ ios: "GreycliffCF-Bold",
51
+ android: "Greycliff-Bold",
52
+ default: "Greycliff-Bold",
53
+ }),
54
+ fontSize: 13,
55
+ lineHeight: 20,
56
+ },
26
57
  textInput: {
27
58
  padding: 0,
28
59
  margin: 0,
@@ -51,14 +82,22 @@ export type TextTransform =
51
82
 
52
83
  export type TextAlignment = "left" | "center";
53
84
 
85
+ export type UnderlineConfiguration = {
86
+ focusedBorderColor: string;
87
+ borderColor: string;
88
+ /** Bottom underline height; 0 = none (pill search uses borderWidth instead) */
89
+ underlineHeight: number;
90
+ underlineMarginTop: number;
91
+ /** Radius of the underline bar itself (bottom border style). */
92
+ underlineCornerRadius: number;
93
+ };
94
+
54
95
  export type BackgroundConfiguration = {
55
96
  defaultColor: string;
56
97
  focusedColor: string;
57
98
  borderColor: string;
58
99
  focusedBorderColor: string;
59
100
  borderWidth: number;
60
- /** Bottom underline height; 0 = none (pill search uses borderWidth instead) */
61
- underlineHeight: number;
62
101
  cornerRadius: number;
63
102
  paddingTop: number;
64
103
  paddingRight: number;
@@ -95,6 +134,9 @@ export type TextConfiguration = {
95
134
  androidLetterSpacing: number;
96
135
  textTransform: TextTransform;
97
136
  alignment: TextAlignment;
137
+ /** Vertical spacing around the input text; drives the gap above the underline. */
138
+ marginTop: number;
139
+ marginBottom: number;
98
140
  };
99
141
 
100
142
  export type LeadingIconConfiguration = {
@@ -117,6 +159,7 @@ export type IconsConfiguration = {
117
159
  };
118
160
 
119
161
  export type InputConfiguration = {
162
+ underline: UnderlineConfiguration;
120
163
  background: BackgroundConfiguration;
121
164
  label: LabelConfiguration;
122
165
  text: TextConfiguration;
@@ -129,7 +172,6 @@ export const DEFAULT_BACKGROUND_CONFIGURATION: BackgroundConfiguration = {
129
172
  borderColor: "rgba(255, 255, 255, 0.55)",
130
173
  focusedBorderColor: "rgba(255, 255, 255, 0.85)",
131
174
  borderWidth: 1,
132
- underlineHeight: 0,
133
175
  cornerRadius: 24,
134
176
  paddingTop: 10,
135
177
  paddingRight: 10,
@@ -165,6 +207,8 @@ export const DEFAULT_TEXT_CONFIGURATION: TextConfiguration = {
165
207
  androidLetterSpacing: 0,
166
208
  textTransform: "default",
167
209
  alignment: "left",
210
+ marginTop: 0,
211
+ marginBottom: 0,
168
212
  };
169
213
 
170
214
  export const DEFAULT_ICONS_CONFIGURATION: IconsConfiguration = {
@@ -180,8 +224,17 @@ export const DEFAULT_ICONS_CONFIGURATION: IconsConfiguration = {
180
224
  },
181
225
  };
182
226
 
227
+ export const DEFAULT_UNDERLINE_CONFIGURATION: UnderlineConfiguration = {
228
+ borderColor: "rgba(255, 255, 255, 0.55)",
229
+ focusedBorderColor: "rgba(255, 255, 255, 0.85)",
230
+ underlineHeight: 0,
231
+ underlineMarginTop: 0,
232
+ underlineCornerRadius: 0,
233
+ };
234
+
183
235
  export const DEFAULT_INPUT_CONFIGURATION: InputConfiguration = {
184
236
  background: DEFAULT_BACKGROUND_CONFIGURATION,
237
+ underline: DEFAULT_UNDERLINE_CONFIGURATION,
185
238
  label: DEFAULT_LABEL_CONFIGURATION,
186
239
  text: DEFAULT_TEXT_CONFIGURATION,
187
240
  icons: DEFAULT_ICONS_CONFIGURATION,
@@ -203,6 +256,7 @@ export type ItemProps = {
203
256
  value?: string;
204
257
  focused?: boolean;
205
258
  focusedClearButton?: boolean;
259
+ validationMessage?: string;
206
260
  onChangeText?: (text: string) => void;
207
261
  onClearPress?: () => void;
208
262
  onFocus?: () => void;
@@ -243,7 +297,7 @@ function shouldShowLabel(label: LabelConfiguration, labelText?: string) {
243
297
  }
244
298
 
245
299
  function isUnderlineLayout(configuration: InputConfiguration) {
246
- return configuration.background.underlineHeight > 0;
300
+ return configuration.underline.underlineHeight > 0;
247
301
  }
248
302
 
249
303
  // ---------------------------------------------------------------------------
@@ -323,7 +377,7 @@ function InputContainer({
323
377
  }
324
378
 
325
379
  type InputUnderlineProps = {
326
- configuration: BackgroundConfiguration;
380
+ configuration: UnderlineConfiguration;
327
381
  focused: boolean;
328
382
  };
329
383
 
@@ -337,7 +391,9 @@ function InputUnderline({ configuration, focused }: InputUnderlineProps) {
337
391
  style={[
338
392
  styles.underline,
339
393
  {
394
+ marginTop: configuration.underlineMarginTop,
340
395
  height: configuration.underlineHeight,
396
+ borderRadius: configuration.underlineCornerRadius,
341
397
  backgroundColor: focused
342
398
  ? configuration.focusedBorderColor
343
399
  : configuration.borderColor,
@@ -427,6 +483,8 @@ function InputField({
427
483
  }),
428
484
  textTransform: getTextTransformStyle(configuration.textTransform),
429
485
  textAlign: configuration.alignment,
486
+ marginTop: configuration.marginTop,
487
+ marginBottom: configuration.marginBottom,
430
488
  },
431
489
  ]}
432
490
  />
@@ -479,12 +537,13 @@ export function AudioPlayerInput({
479
537
  value = "",
480
538
  focused = false,
481
539
  focusedClearButton = false,
540
+ validationMessage,
482
541
  onChangeText,
483
542
  onClearPress,
484
543
  onFocus,
485
544
  onBlur,
486
545
  }: ItemProps) {
487
- const { background, label, text, icons } = configuration;
546
+ const { background, label, text, icons, underline } = configuration;
488
547
  const inputRef = useRef<TextInputRef>(null);
489
548
  const underlineLayout = isUnderlineLayout(configuration);
490
549
  const showLabel = shouldShowLabel(label, data.label);
@@ -545,109 +604,125 @@ export function AudioPlayerInput({
545
604
  </>
546
605
  ) : null}
547
606
  {underlineLayout ? (
548
- <InputUnderline configuration={background} focused={focused} />
607
+ <InputUnderline configuration={underline} focused={focused} />
549
608
  ) : null}
550
609
  </InputContainer>
551
610
  </Pressable>
552
611
  );
553
612
 
554
- if (!showLabel || !data.label) {
555
- return inputRow;
556
- }
557
-
558
613
  return (
559
614
  <View style={styles.column}>
560
- <InputLabel text={data.label} configuration={label} />
561
- <View style={{ height: background.verticalGutter }} />
615
+ {showLabel && data.label ? (
616
+ <>
617
+ <InputLabel text={data.label} configuration={label} />
618
+ <View style={{ height: background.verticalGutter }} />
619
+ </>
620
+ ) : null}
562
621
  {inputRow}
622
+ {validationMessage ? (
623
+ <View style={styles.validationMessage} accessibilityRole="alert">
624
+ <Image
625
+ source={{
626
+ uri: resolveDefaultAssetUri(
627
+ require("../../../../assets/empty-Info.png")
628
+ ),
629
+ }}
630
+ style={styles.validationMessageIcon}
631
+ />
632
+ <Text
633
+ style={styles.validationMessageText}
634
+ numberOfLines={1}
635
+ ellipsizeMode="tail"
636
+ >
637
+ {validationMessage}
638
+ </Text>
639
+ </View>
640
+ ) : null}
563
641
  </View>
564
642
  );
565
643
  }
566
644
 
567
645
  // ---------------------------------------------------------------------------
568
- // Variant presets — collections of configuration keys (not a variant field)
646
+ // Variant configurations
569
647
  // ---------------------------------------------------------------------------
570
648
 
571
649
  /** Search pill — leading icon + clear button */
572
650
  export const VARIANT_SEARCH_INPUT: InputConfiguration =
573
651
  DEFAULT_INPUT_CONFIGURATION;
574
652
 
575
- /** Name playlist — centered title + label + underline (screenshot) */
653
+ /**
654
+ * Name playlist — centered title + 32pt text over a rounded bottom underline.
655
+ *
656
+ * Values mirror the manifest configuration the
657
+ * `quick-brick-component-text-field` plugin renders from; the comment on each
658
+ * line names the reference key it comes from.
659
+ */
576
660
  export const VARIANT_NAME_PLAYLIST_INPUT: InputConfiguration = {
577
661
  background: {
578
- defaultColor: "transparent",
579
- focusedColor: "transparent",
580
- borderColor: "rgba(255, 255, 255, 0.35)",
581
- focusedBorderColor: "rgba(255, 255, 255, 0.55)",
662
+ // text_input_background_*_background_color
663
+ defaultColor: "rgba(30,30,30,0.00)",
664
+ focusedColor: "rgba(46,46,46,0.00)",
665
+ // text_input_style_border_*_border_color
666
+ borderColor: "rgba(255,255,255,0.25)",
667
+ focusedBorderColor: "rgba(255,255,255,1.00)",
668
+ // border_border_style is "bottom", so the box border is off and the
669
+ // underline below draws the border instead.
582
670
  borderWidth: 0,
583
- underlineHeight: 1,
584
671
  cornerRadius: 0,
672
+ // text_input_style_input_padding_*
585
673
  paddingTop: 0,
586
674
  paddingRight: 0,
587
- paddingBottom: 10,
675
+ paddingBottom: 0,
588
676
  paddingLeft: 0,
589
- horizontalGutter: 0,
590
- verticalGutter: 16,
591
- height: 0,
677
+ horizontalGutter: 0, // text_input_style_input_horizontal_gutter
678
+ verticalGutter: 0, // component_style_vertical_gutter
679
+ height: 0, // hug content
680
+ },
681
+ underline: {
682
+ borderColor: "rgba(255,255,255,0.25)",
683
+ focusedBorderColor: "rgba(255,255,255,1.00)",
684
+ underlineHeight: 2, // text_input_style_border_border_size
685
+ // The gap above the bar comes from the text's marginBottom, matching how
686
+ // the plugin applies `text_label_margin_bottom` to the input itself.
687
+ underlineMarginTop: 0,
688
+ underlineCornerRadius: 4, // ..._border_bottom_border_corner_radius
592
689
  },
593
690
  label: {
594
- enabled: true,
595
- fontColor: "rgba(142, 142, 147, 1)",
596
- iosFontFamily: "SFProText-Regular",
597
- androidFontFamily: "Roboto",
598
- fontSize: 15,
599
- lineHeight: 20,
600
- iosLetterSpacing: -0.2,
691
+ enabled: true, // title_enable
692
+ fontColor: "rgba(255,255,255,0.50)", // title_style_color
693
+ iosFontFamily: "GreycliffCF-Bold", // title_style_ios_font_family
694
+ androidFontFamily: "Greycliff-Bold", // title_style_android_font_family
695
+ fontSize: 14, // title_style_font_size
696
+ lineHeight: 32, // title_style_line_height
697
+ iosLetterSpacing: 0,
601
698
  androidLetterSpacing: 0,
602
- textTransform: "default",
699
+ textTransform: "default", // title_style_text_transform: "none"
603
700
  },
604
701
  text: {
605
- fontColor: "#FFFFFF",
606
- focusedFontColor: "#FFFFFF",
607
- placeholderColor: "rgba(142, 142, 147, 1)",
608
- cursorColor: "#FFFFFF",
609
- iosFontFamily: "SFProText-Bold",
610
- androidFontFamily: "Roboto-Bold",
702
+ // text_input_style_text_label_*
703
+ fontColor: "rgba(255,255,255,1.00)", // active_label_color
704
+ focusedFontColor: "rgba(255,255,255,1.00)",
705
+ placeholderColor: "rgba(255,255,255,0.50)", // placeholder_label_color
706
+ cursorColor: "rgba(249,183,72,1.00)", // text_input_style_cursor_cursor_color
707
+ iosFontFamily: "GreycliffCF-Bold",
708
+ androidFontFamily: "Greycliff-Bold",
611
709
  fontSize: 32,
612
710
  lineHeight: 40,
613
- iosLetterSpacing: -0.6,
711
+ iosLetterSpacing: 0,
614
712
  androidLetterSpacing: 0,
615
713
  textTransform: "default",
616
714
  alignment: "center",
715
+ marginTop: 20, // text_label_margin_top
716
+ marginBottom: 20, // text_label_margin_bottom
617
717
  },
618
718
  icons: {
619
719
  width: 20,
620
720
  height: 20,
621
721
  leadingIcon: { enabled: false },
622
722
  trailingIcon: {
623
- enabled: false,
723
+ enabled: false, // clear_button_enable
624
724
  backgroundColor: "rgba(58, 58, 60, 1)",
625
725
  focusedBackgroundColor: "rgba(72, 72, 74, 1)",
626
726
  },
627
727
  },
628
728
  };
629
-
630
- /** Text only search pill — no leading icon */
631
- export const VARIANT_TEXT_ONLY_INPUT: InputConfiguration = {
632
- background: DEFAULT_BACKGROUND_CONFIGURATION,
633
- label: DEFAULT_LABEL_CONFIGURATION,
634
- text: DEFAULT_TEXT_CONFIGURATION,
635
- icons: {
636
- ...DEFAULT_ICONS_CONFIGURATION,
637
- leadingIcon: { enabled: false },
638
- },
639
- };
640
-
641
- /** Search without clear button */
642
- export const VARIANT_SEARCH_WITHOUT_CLEAR: InputConfiguration = {
643
- background: DEFAULT_BACKGROUND_CONFIGURATION,
644
- label: DEFAULT_LABEL_CONFIGURATION,
645
- text: DEFAULT_TEXT_CONFIGURATION,
646
- icons: {
647
- ...DEFAULT_ICONS_CONFIGURATION,
648
- trailingIcon: {
649
- ...DEFAULT_ICONS_CONFIGURATION.trailingIcon,
650
- enabled: false,
651
- },
652
- },
653
- };