@applicaster/zapp-react-native-utils 16.0.0-rc.124 → 16.0.0-rc.125

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.
@@ -2,6 +2,22 @@ import { openBottomSheetAction } from "../openBottomSheet";
2
2
  import { actionExecutor, ActionResult } from "../../ActionExecutor";
3
3
  import { modalOrchestrator } from "../../../modalState/ModalOrchestrator";
4
4
 
5
+ jest.mock("@applicaster/zapp-pipes-v2-client", () => ({
6
+ PipesClientResponseHelper: jest.fn(() => ({ error: null })),
7
+ RequestBuilder: jest.fn(() => ({
8
+ setEntryContext: jest.fn().mockReturnThis(),
9
+ setScreenContext: jest.fn().mockReturnThis(),
10
+ setUrl: jest.fn().mockReturnThis(),
11
+ buildAxiosRequest: jest.fn().mockResolvedValue(undefined),
12
+ call: jest.fn().mockResolvedValue({
13
+ response: {
14
+ entry: [],
15
+ extensions: { dynamic_collection_options: { operations: "add" } },
16
+ },
17
+ }),
18
+ })),
19
+ }));
20
+
5
21
  jest.mock("../../../modalState/store", () => ({
6
22
  openBottomSheetModal: jest.fn(),
7
23
  }));
@@ -165,6 +181,62 @@ describe("openBottomSheetAction inline items", () => {
165
181
  expect(menu.content.emptyMessage).toBe("Queued items will be added here");
166
182
  });
167
183
 
184
+ it("forwards content.operationButtons onto the menu", async () => {
185
+ const result = await openBottomSheetAction({
186
+ type: "openBottomSheet",
187
+ options: {
188
+ header: { title: "Playlists" },
189
+ content: {
190
+ items: [{ id: "p1", title: "Playlist 1" }],
191
+ operationButtons: {
192
+ add: {
193
+ title: "Create New Playlist",
194
+ iconURL: "https://example.com/add.png",
195
+ },
196
+ },
197
+ },
198
+ },
199
+ } as any);
200
+
201
+ expect(result).toBe(ActionResult.Success);
202
+
203
+ const [menu] = (modalOrchestrator.open as jest.Mock).mock.calls[0];
204
+
205
+ expect(menu.content.operationButtons).toEqual({
206
+ add: {
207
+ title: "Create New Playlist",
208
+ iconURL: "https://example.com/add.png",
209
+ },
210
+ });
211
+ });
212
+
213
+ it("preserves Add presentation when loading itemsUrl content", async () => {
214
+ const result = await openBottomSheetAction({
215
+ type: "openBottomSheet",
216
+ options: {
217
+ content: {
218
+ itemsUrl: "https://example.com/collections",
219
+ operationButtons: {
220
+ add: {
221
+ title: "Create Collection",
222
+ iconURL: "file:///bundled-add.png",
223
+ },
224
+ },
225
+ },
226
+ },
227
+ });
228
+
229
+ expect(result).toBe(ActionResult.Success);
230
+ const [menu] = (modalOrchestrator.open as jest.Mock).mock.calls[0];
231
+
232
+ expect(menu.content).toMatchObject({
233
+ operationButtons: {
234
+ add: { title: "Create Collection", iconURL: "file:///bundled-add.png" },
235
+ },
236
+ dynamicCollection: { operations: ["add"] },
237
+ });
238
+ });
239
+
168
240
  it("pushes a new sheet by default even when another sheet is already open", async () => {
169
241
  (modalOrchestrator as any).stackSize = 1;
170
242
 
@@ -290,6 +290,7 @@ export async function openBottomSheetAction(
290
290
  themePluginId,
291
291
  styleOverrides: styleOverrides ?? content?.styleOverrides,
292
292
  emptyMessage: content?.emptyMessage,
293
+ operationButtons: content?.operationButtons,
293
294
  context,
294
295
  },
295
296
  };
@@ -171,6 +171,17 @@ describe("parseModalBlocksConfiguration", () => {
171
171
  expect(result.item.checkbox.default).toBeUndefined();
172
172
  expect(result.item.actionButtons.default).toBeUndefined();
173
173
  });
174
+
175
+ it("parses the generic button leading icon asset", () => {
176
+ const result = parseModalBlocksConfiguration(
177
+ { "button.leading_icon.asset": "https://example.com/add.png" },
178
+ "playlist-experience"
179
+ );
180
+
181
+ expect(result.button.leadingIcon.default?.asset).toBe(
182
+ "https://example.com/add.png"
183
+ );
184
+ });
174
185
  });
175
186
 
176
187
  describe("getEmptyModalBlocksStructure", () => {
@@ -45,6 +45,7 @@ function menuToModalArgs(
45
45
  summary: menu.header?.subtitle,
46
46
  styleOverrides: menu.content.styleOverrides,
47
47
  emptyMessage: menu.content.emptyMessage,
48
+ operationButtons: menu.content.operationButtons,
48
49
  onPress: onItemPress,
49
50
  viewModel,
50
51
  },
@@ -60,4 +60,27 @@ describe("ModalOrchestrator phase 3", () => {
60
60
 
61
61
  expect(props.emptyMessage).toBe("Queued items will be added here");
62
62
  });
63
+
64
+ it("forwards operationButtons onto the sheet props unchanged", () => {
65
+ const operationButtons = {
66
+ add: {
67
+ title: "Create New Playlist",
68
+ iconURL: "https://example.com/add.png",
69
+ },
70
+ };
71
+
72
+ modalOrchestrator.open({
73
+ header: { title: "Playlists" },
74
+ content: {
75
+ title: "Playlists",
76
+ items: [],
77
+ operationButtons,
78
+ },
79
+ });
80
+
81
+ const props = (modalStore.getState().modalState.screen as any)
82
+ ?.modalBottomSheetContentProps;
83
+
84
+ expect(props.operationButtons).toEqual(operationButtons);
85
+ });
63
86
  });
@@ -23,6 +23,8 @@ export type {
23
23
  SecondaryAction,
24
24
  SelectMode,
25
25
  SelectionBehavior,
26
+ OperationButton,
27
+ OperationButtons,
26
28
  } from "./types";
27
29
 
28
30
  export {
@@ -1,3 +1,5 @@
1
+ import type { EntryAction } from "../entryActions/types";
2
+
1
3
  export interface Header {
2
4
  title: string;
3
5
  subtitle?: string;
@@ -107,6 +109,13 @@ export interface DynamicCollectionOptions {
107
109
  events?: Record<CollectionScopedOperation | string, Action[]>;
108
110
  }
109
111
 
112
+ /** Presentation of a sheet-synthesized operation control; same fields as an entry action button. */
113
+ export type OperationButton = Pick<EntryAction["button"], "title" | "iconURL">;
114
+
115
+ export type OperationButtons = Partial<
116
+ Record<CollectionScopedOperation | string, OperationButton>
117
+ >;
118
+
110
119
  export interface Content {
111
120
  title: string;
112
121
  stickyTitle?: boolean;
@@ -120,6 +129,8 @@ export interface Content {
120
129
  styleOverrides?: Record<string, any>;
121
130
  /** Shown under Next Up when the queue sheet has no upcoming items. */
122
131
  emptyMessage?: string;
132
+ /** Producer-owned presentation for sheet-synthesized operation controls (e.g. `add`). */
133
+ operationButtons?: OperationButtons;
123
134
  context?: Record<string, any>;
124
135
  }
125
136
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "16.0.0-rc.124",
3
+ "version": "16.0.0-rc.125",
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": "16.0.0-rc.124",
30
+ "@applicaster/applicaster-types": "16.0.0-rc.125",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",