@applicaster/zapp-react-native-ui-components 15.1.13-alpha.1034774223 → 15.1.13

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 (40) hide show
  1. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +1 -0
  2. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
  3. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +87 -33
  4. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +74 -57
  5. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +107 -142
  6. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +159 -410
  7. package/Components/ModalComponent/AudioPlayer/Components/index.ts +4 -8
  8. package/Components/ModalComponent/BottomSheetModalContent.tsx +61 -379
  9. package/Components/ModalComponent/Button/index.tsx +3 -5
  10. package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
  11. package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
  12. package/Components/ModalComponent/Header/index.tsx +7 -20
  13. package/Components/ModalComponent/Header/utils.ts +1 -1
  14. package/Components/ModalComponent/index.tsx +0 -11
  15. package/Components/ModalComponent/utils.ts +21 -82
  16. package/package.json +5 -6
  17. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +0 -54
  18. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +0 -21
  19. package/Components/ModalComponent/ActionsBottomSheet/index.ts +0 -9
  20. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +0 -58
  21. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +0 -653
  22. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +0 -89
  23. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +0 -230
  24. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +0 -332
  25. package/Components/ModalComponent/ModalBlocksStyleContext.tsx +0 -10
  26. package/Components/ModalComponent/SortableList.tsx +0 -142
  27. package/Components/ModalComponent/SortableList.web.tsx +0 -102
  28. package/Components/ModalComponent/TextInputContent.tsx +0 -100
  29. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +0 -238
  30. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +0 -120
  31. package/Components/ModalComponent/__tests__/showTextInput.test.ts +0 -95
  32. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +0 -66
  33. package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +0 -78
  34. package/Components/ModalComponent/presets/index.ts +0 -27
  35. package/Components/ModalComponent/presets/selectableCell.tsx +0 -28
  36. package/Components/ModalComponent/presets/standardCell.tsx +0 -41
  37. package/Components/ModalComponent/presets/types.ts +0 -35
  38. package/Components/ModalComponent/showTextInput.ts +0 -43
  39. package/Hooks/useEntryActionsExpander.ts +0 -63
  40. /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.tsx → Hero.js} +0 -0
@@ -102,6 +102,7 @@ export const ActionButton = React.memo(function ActionButtonComponent(
102
102
  testID={props?.testID || `${item?.id}`}
103
103
  accessibilityLabel={props?.accessibilityLabel || `${item?.id}`}
104
104
  accessibilityHint={props?.accessibilityHint}
105
+ accessibilityRole="button"
105
106
  accessible={!!(props?.testID || props?.accessibilityLabel)}
106
107
  style={props?.style}
107
108
  >
@@ -106,6 +106,7 @@ function ButtonComponent(props: Props) {
106
106
  onPress={onPress}
107
107
  testID={props?.testID || `${item?.id}`}
108
108
  accessibilityLabel={props?.accessibilityLabel || `${item?.id}`}
109
+ accessibilityRole="button"
109
110
  accessible={!!(props?.testID || props?.accessibilityLabel)}
110
111
  style={props?.style}
111
112
  >
@@ -11,20 +11,31 @@
11
11
  */
12
12
 
13
13
  import React from "react";
14
- import {
15
- Image,
16
- Platform,
17
- Pressable,
18
- StyleSheet,
19
- Text,
20
- View,
21
- } from "react-native";
14
+ import { Image, Platform, StyleSheet, Text, View } from "react-native";
22
15
 
23
16
  const styles = StyleSheet.create({
24
17
  row: {
25
18
  flexDirection: "row",
26
19
  alignItems: "center",
27
20
  },
21
+ demoScreen: {
22
+ flex: 1,
23
+ backgroundColor: "#1C1C1E",
24
+ paddingTop: 64,
25
+ paddingHorizontal: 16,
26
+ gap: 12,
27
+ },
28
+ demoHeading: {
29
+ color: "#FFFFFF",
30
+ fontSize: 20,
31
+ fontWeight: "600",
32
+ marginBottom: 8,
33
+ },
34
+ demoLabel: {
35
+ color: "#999999",
36
+ fontSize: 13,
37
+ marginTop: 8,
38
+ },
28
39
  });
29
40
 
30
41
  // ---------------------------------------------------------------------------
@@ -112,11 +123,10 @@ export type ActionData = {
112
123
  showTrailingChevron?: boolean;
113
124
  };
114
125
 
115
- export type AudioPlayerActionProps = {
126
+ export type ItemProps = {
116
127
  configuration: ActionConfiguration;
117
128
  data: ActionData;
118
129
  focused?: boolean;
119
- onPress?: () => void;
120
130
  };
121
131
 
122
132
  // ---------------------------------------------------------------------------
@@ -177,32 +187,28 @@ type ActionContainerProps = {
177
187
  configuration: BackgroundConfiguration;
178
188
  focused: boolean;
179
189
  children: React.ReactNode;
180
- onPress?: () => void;
181
190
  };
182
191
 
183
192
  function ActionContainer({
184
193
  configuration,
185
194
  focused,
186
195
  children,
187
- onPress,
188
196
  }: ActionContainerProps) {
189
197
  return (
190
- <Pressable
191
- onPress={onPress}
192
- style={({ pressed }) => ({
193
- backgroundColor:
194
- pressed || focused
195
- ? configuration.focusedColor
196
- : configuration.defaultColor,
198
+ <View
199
+ style={{
200
+ backgroundColor: focused
201
+ ? configuration.focusedColor
202
+ : configuration.defaultColor,
197
203
  borderRadius: configuration.cornerRadius,
198
204
  paddingTop: CONTAINER_SPEC.paddingTop,
199
205
  paddingRight: CONTAINER_SPEC.paddingRight,
200
206
  paddingBottom: CONTAINER_SPEC.paddingBottom,
201
207
  paddingLeft: CONTAINER_SPEC.paddingLeft,
202
- })}
208
+ }}
203
209
  >
204
210
  {children}
205
- </Pressable>
211
+ </View>
206
212
  );
207
213
  }
208
214
 
@@ -273,15 +279,10 @@ function ActionTrailingIcon({ configuration }: ActionTrailingIconProps) {
273
279
  }
274
280
 
275
281
  // ---------------------------------------------------------------------------
276
- // AudioPlayerAction
282
+ // Item
277
283
  // ---------------------------------------------------------------------------
278
284
 
279
- export function AudioPlayerAction({
280
- configuration,
281
- data,
282
- focused = false,
283
- onPress,
284
- }: AudioPlayerActionProps) {
285
+ export function Item({ configuration, data, focused = false }: ItemProps) {
285
286
  const { background, title, trailingIcon } = configuration;
286
287
  const { title: label, leadingActionType, showTrailingChevron } = data;
287
288
 
@@ -289,11 +290,7 @@ export function AudioPlayerAction({
289
290
  const showTrailing = shouldShowTrailingIcon(showTrailingChevron);
290
291
 
291
292
  return (
292
- <ActionContainer
293
- configuration={background}
294
- focused={focused}
295
- onPress={onPress}
296
- >
293
+ <ActionContainer configuration={background} focused={focused}>
297
294
  <View style={styles.row}>
298
295
  {showLeading ? (
299
296
  <>
@@ -312,3 +309,60 @@ export function AudioPlayerAction({
312
309
  </ActionContainer>
313
310
  );
314
311
  }
312
+
313
+ // ---------------------------------------------------------------------------
314
+ // Demo
315
+ // ---------------------------------------------------------------------------
316
+
317
+ export default function App() {
318
+ return (
319
+ <View style={styles.demoScreen}>
320
+ <Text style={styles.demoHeading}>Modal Action Building Block</Text>
321
+
322
+ <Text style={styles.demoLabel}>
323
+ Leading icon + text — Add To Queue (focused)
324
+ </Text>
325
+ <Item
326
+ configuration={DEFAULT_ACTION_CONFIGURATION}
327
+ data={{ title: "Add To Queue", leadingActionType: "addToQueue" }}
328
+ focused
329
+ />
330
+
331
+ <Text style={styles.demoLabel}>
332
+ Leading icon + text + trailing chevron — Add To Playlist
333
+ </Text>
334
+ <Item
335
+ configuration={DEFAULT_ACTION_CONFIGURATION}
336
+ data={{
337
+ title: "Add To Playlist",
338
+ leadingActionType: "addToPlaylist",
339
+ showTrailingChevron: true,
340
+ }}
341
+ />
342
+
343
+ <Text style={styles.demoLabel}>Text only — Go To Playlist</Text>
344
+ <Item
345
+ configuration={DEFAULT_ACTION_CONFIGURATION}
346
+ data={{ title: "Go To Playlist" }}
347
+ />
348
+
349
+ <Text style={styles.demoLabel}>Leading icon + text — Favorite</Text>
350
+ <Item
351
+ configuration={DEFAULT_ACTION_CONFIGURATION}
352
+ data={{ title: "Favorite", leadingActionType: "favorite" }}
353
+ />
354
+
355
+ <Text style={styles.demoLabel}>Leading icon + text — Share</Text>
356
+ <Item
357
+ configuration={DEFAULT_ACTION_CONFIGURATION}
358
+ data={{ title: "Share", leadingActionType: "share" }}
359
+ />
360
+
361
+ <Text style={styles.demoLabel}>Text only — Go To Artist</Text>
362
+ <Item
363
+ configuration={DEFAULT_ACTION_CONFIGURATION}
364
+ data={{ title: "Go To Artist" }}
365
+ />
366
+ </View>
367
+ );
368
+ }
@@ -9,14 +9,7 @@
9
9
  */
10
10
 
11
11
  import React from "react";
12
- import {
13
- Image,
14
- Platform,
15
- Pressable,
16
- StyleSheet,
17
- Text,
18
- View,
19
- } from "react-native";
12
+ import { Image, Platform, StyleSheet, Text, View } from "react-native";
20
13
 
21
14
  const styles = StyleSheet.create({
22
15
  container: {
@@ -32,6 +25,24 @@ const styles = StyleSheet.create({
32
25
  title: {
33
26
  textAlign: "center",
34
27
  },
28
+ demoScreen: {
29
+ flex: 1,
30
+ backgroundColor: "#1C1C1E",
31
+ paddingTop: 64,
32
+ paddingHorizontal: 24,
33
+ gap: 12,
34
+ },
35
+ demoHeading: {
36
+ color: "#FFFFFF",
37
+ fontSize: 20,
38
+ fontWeight: "600",
39
+ marginBottom: 8,
40
+ },
41
+ demoLabel: {
42
+ color: "#999999",
43
+ fontSize: 13,
44
+ marginTop: 8,
45
+ },
35
46
  });
36
47
 
37
48
  // ---------------------------------------------------------------------------
@@ -81,8 +92,6 @@ export type LeadingIconConfiguration = {
81
92
  enabled: boolean;
82
93
  /** Decides which icon will be displayed when enabled */
83
94
  actionType?: ButtonActionType;
84
- /** Optional Studio / modal-blocks asset URI (overrides actionType mapping) */
85
- asset?: string;
86
95
  };
87
96
 
88
97
  export type IconsConfiguration = {
@@ -139,12 +148,11 @@ export type ButtonData = {
139
148
  disabled?: boolean;
140
149
  };
141
150
 
142
- export type AudioPlayerButtonProps = {
151
+ export type ItemProps = {
143
152
  configuration: ButtonConfiguration;
144
153
  data: ButtonData;
145
154
  disabled?: boolean;
146
155
  focused?: boolean;
147
- onPress?: () => void;
148
156
  };
149
157
 
150
158
  // ---------------------------------------------------------------------------
@@ -162,7 +170,7 @@ const ACTION_ICON_ASSETS: Record<ButtonActionType, string> = {
162
170
  confirm:
163
171
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAJElEQVR42mNgGAWjYBSQCv4TwKMWDHELho/hNE/3o2AUDDcAAPv0QMAyy1CtAAAAAElFTkSuQmCC",
164
172
  cancel:
165
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAASElEQVR42mNgGAWjGvynkVoUTf+pqA6nxv8UqiHbEooNx2cQ1QzHZiDVDcdlCcOQsoCmQUTTSKZpMqV5RqNLUUHTwm4UDBMAALBLQ73LTvoyAAAAAElFTkSuQmCC",
173
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAASElEQVR42mNgGAUjGvynkVoUTf+pqA6nxv8UqiHbEooNx2cQ1QzHZiDVDcdlCcOQsoCmQUTTSKZpMqV5RqNLUUHTwm4UDBMAALBLQ73LTvoyAAAAAElFTkSuQmCC",
166
174
  };
167
175
 
168
176
  function getTextTransformStyle(
@@ -172,9 +180,7 @@ function getTextTransformStyle(
172
180
  }
173
181
 
174
182
  function shouldShowLeadingIcon(leadingIcon: LeadingIconConfiguration) {
175
- return (
176
- leadingIcon.enabled && (!!leadingIcon.actionType || !!leadingIcon.asset)
177
- );
183
+ return leadingIcon.enabled && !!leadingIcon.actionType;
178
184
  }
179
185
 
180
186
  // ---------------------------------------------------------------------------
@@ -186,7 +192,6 @@ type ButtonContainerProps = {
186
192
  disabled: boolean;
187
193
  configuration: BackgroundConfiguration;
188
194
  children: React.ReactNode;
189
- onPress?: () => void;
190
195
  };
191
196
 
192
197
  function ButtonContainer({
@@ -194,22 +199,19 @@ function ButtonContainer({
194
199
  disabled,
195
200
  configuration,
196
201
  children,
197
- onPress,
198
202
  }: ButtonContainerProps) {
199
- const defaultBgColor = disabled
203
+ const backgroundColor = disabled
200
204
  ? configuration.inactiveColor
201
205
  : focused
202
206
  ? configuration.focusedColor
203
207
  : configuration.defaultColor;
204
208
 
205
209
  return (
206
- <Pressable
207
- onPress={disabled ? undefined : onPress}
208
- style={({ pressed }) => [
210
+ <View
211
+ style={[
209
212
  styles.container,
210
213
  {
211
- backgroundColor:
212
- pressed && !disabled ? configuration.focusedColor : defaultBgColor,
214
+ backgroundColor,
213
215
  borderRadius: configuration.cornerRadius,
214
216
  paddingTop: configuration.paddingTop,
215
217
  paddingRight: configuration.paddingRight,
@@ -219,7 +221,7 @@ function ButtonContainer({
219
221
  ]}
220
222
  >
221
223
  {children}
222
- </Pressable>
224
+ </View>
223
225
  );
224
226
  }
225
227
 
@@ -272,7 +274,7 @@ function ButtonTitle({
272
274
  }
273
275
 
274
276
  type ButtonLeadingIconProps = {
275
- actionType?: ButtonActionType;
277
+ actionType: ButtonActionType;
276
278
  configuration: IconsConfiguration;
277
279
  };
278
280
 
@@ -280,17 +282,9 @@ function ButtonLeadingIcon({
280
282
  actionType,
281
283
  configuration,
282
284
  }: ButtonLeadingIconProps) {
283
- const asset =
284
- configuration.leadingIcon.asset ||
285
- (actionType ? ACTION_ICON_ASSETS[actionType] : undefined);
286
-
287
- if (!asset) {
288
- return null;
289
- }
290
-
291
285
  return (
292
286
  <Image
293
- source={{ uri: asset }}
287
+ source={{ uri: ACTION_ICON_ASSETS[actionType] }}
294
288
  style={{
295
289
  width: configuration.width,
296
290
  height: configuration.height,
@@ -301,32 +295,20 @@ function ButtonLeadingIcon({
301
295
  }
302
296
 
303
297
  // ---------------------------------------------------------------------------
304
- // AudioPlayerButton — single building block driven by configuration + data
298
+ // Item — single building block driven by configuration + data
305
299
  // ---------------------------------------------------------------------------
306
300
 
307
- import { useModalBlocksStyle } from "../../ModalBlocksStyleContext";
308
- import { mergeButtonConfiguration } from "../utils/mergeStyles";
309
-
310
- export function AudioPlayerButton({
301
+ export function Item({
311
302
  configuration,
312
303
  data,
313
304
  disabled,
314
305
  focused = false,
315
- onPress,
316
- }: AudioPlayerButtonProps) {
317
- const modalBlocksStyle = useModalBlocksStyle();
318
- const buttonBlock = modalBlocksStyle?.button;
319
- const actionBlock = modalBlocksStyle?.action;
320
-
321
- const effectiveConfig = React.useMemo(() => {
322
- return mergeButtonConfiguration(configuration, buttonBlock, actionBlock);
323
- }, [configuration, buttonBlock, actionBlock]);
324
-
306
+ }: ItemProps) {
325
307
  const {
326
- background: effectiveBgConfig,
327
- title: effectiveTitleConfig,
308
+ background: backgroundConfiguration,
309
+ title: titleConfiguration,
328
310
  icons: iconsConfiguration,
329
- } = effectiveConfig;
311
+ } = configuration;
330
312
 
331
313
  const { title } = data;
332
314
  const isDisabled = disabled ?? data.disabled ?? false;
@@ -338,8 +320,7 @@ export function AudioPlayerButton({
338
320
  <ButtonContainer
339
321
  focused={focused}
340
322
  disabled={isDisabled}
341
- configuration={effectiveBgConfig}
342
- onPress={onPress}
323
+ configuration={backgroundConfiguration}
343
324
  >
344
325
  <View style={styles.contentRow}>
345
326
  {showIcon ? (
@@ -348,14 +329,14 @@ export function AudioPlayerButton({
348
329
  actionType={leadingIcon.actionType}
349
330
  configuration={iconsConfiguration}
350
331
  />
351
- <View style={{ width: effectiveBgConfig.horizontalGutter }} />
332
+ <View style={{ width: backgroundConfiguration.horizontalGutter }} />
352
333
  </>
353
334
  ) : null}
354
335
  <ButtonTitle
355
336
  title={title}
356
337
  focused={focused}
357
338
  disabled={isDisabled}
358
- configuration={effectiveTitleConfig}
339
+ configuration={titleConfiguration}
359
340
  />
360
341
  </View>
361
342
  </ButtonContainer>
@@ -405,3 +386,39 @@ export const VARIANT_LARGE_ICON: ButtonConfiguration = {
405
386
  },
406
387
  },
407
388
  };
389
+
390
+ export default function App() {
391
+ return (
392
+ <View style={styles.demoScreen}>
393
+ <Text style={styles.demoHeading}>Modal Button Building Block</Text>
394
+
395
+ <Text style={styles.demoLabel}>Variant 1 — Text only (confirmation)</Text>
396
+ <Item configuration={VARIANT_TEXT_ONLY} data={{ title: "Confirm" }} />
397
+
398
+ <Text style={styles.demoLabel}>Variant 2 — Leading icon + text</Text>
399
+ <Item
400
+ configuration={VARIANT_WITH_ICON}
401
+ data={{ title: "Add To Playlist" }}
402
+ />
403
+
404
+ <Text style={styles.demoLabel}>Inactive state</Text>
405
+ <Item
406
+ configuration={VARIANT_TEXT_ONLY}
407
+ data={{ title: "Unavailable" }}
408
+ disabled
409
+ />
410
+
411
+ <Text style={styles.demoLabel}>Custom title config — uppercase</Text>
412
+ <Item
413
+ configuration={VARIANT_UPPERCASE_TITLE}
414
+ data={{ title: "Save Changes" }}
415
+ />
416
+
417
+ <Text style={styles.demoLabel}>Custom icons config — 32×32</Text>
418
+ <Item
419
+ configuration={VARIANT_LARGE_ICON}
420
+ data={{ title: "Add To Queue" }}
421
+ />
422
+ </View>
423
+ );
424
+ }