@thoughtspot/visual-embed-sdk 1.38.0-alpha.1 → 1.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/embed/app.d.ts +96 -156
  3. package/cjs/src/embed/app.d.ts.map +1 -1
  4. package/cjs/src/embed/app.js +6 -3
  5. package/cjs/src/embed/app.js.map +1 -1
  6. package/cjs/src/embed/app.spec.js +10 -0
  7. package/cjs/src/embed/app.spec.js.map +1 -1
  8. package/cjs/src/embed/bodyless-conversation.d.ts +4 -4
  9. package/cjs/src/embed/bodyless-conversation.d.ts.map +1 -1
  10. package/cjs/src/embed/bodyless-conversation.js +1 -1
  11. package/cjs/src/embed/bodyless-conversation.js.map +1 -1
  12. package/cjs/src/embed/conversation.d.ts +22 -11
  13. package/cjs/src/embed/conversation.d.ts.map +1 -1
  14. package/cjs/src/embed/conversation.js +1 -1
  15. package/cjs/src/embed/conversation.js.map +1 -1
  16. package/cjs/src/embed/liveboard.d.ts +110 -167
  17. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  18. package/cjs/src/embed/liveboard.js +4 -1
  19. package/cjs/src/embed/liveboard.js.map +1 -1
  20. package/cjs/src/embed/liveboard.spec.js +11 -0
  21. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  22. package/cjs/src/embed/sage.d.ts +17 -2
  23. package/cjs/src/embed/sage.d.ts.map +1 -1
  24. package/cjs/src/embed/sage.js +2 -0
  25. package/cjs/src/embed/sage.js.map +1 -1
  26. package/cjs/src/embed/search-bar.d.ts +16 -6
  27. package/cjs/src/embed/search-bar.d.ts.map +1 -1
  28. package/cjs/src/embed/search-bar.js.map +1 -1
  29. package/cjs/src/embed/search.d.ts +46 -14
  30. package/cjs/src/embed/search.d.ts.map +1 -1
  31. package/cjs/src/embed/search.js.map +1 -1
  32. package/cjs/src/embed/ts-embed.d.ts +19 -2
  33. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  34. package/cjs/src/embed/ts-embed.js +49 -0
  35. package/cjs/src/embed/ts-embed.js.map +1 -1
  36. package/cjs/src/embed/ts-embed.spec.js +45 -4
  37. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  38. package/cjs/src/index.d.ts +2 -2
  39. package/cjs/src/index.d.ts.map +1 -1
  40. package/cjs/src/index.js +2 -1
  41. package/cjs/src/index.js.map +1 -1
  42. package/cjs/src/react/all-types-export.d.ts +1 -1
  43. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  44. package/cjs/src/react/all-types-export.js +2 -1
  45. package/cjs/src/react/all-types-export.js.map +1 -1
  46. package/cjs/src/react/index.d.ts +1 -1
  47. package/cjs/src/react/index.d.ts.map +1 -1
  48. package/cjs/src/react/index.js +1 -1
  49. package/cjs/src/react/util.d.ts +7 -4
  50. package/cjs/src/react/util.d.ts.map +1 -1
  51. package/cjs/src/react/util.js.map +1 -1
  52. package/cjs/src/types.d.ts +482 -251
  53. package/cjs/src/types.d.ts.map +1 -1
  54. package/cjs/src/types.js +31 -14
  55. package/cjs/src/types.js.map +1 -1
  56. package/cjs/src/utils/graphql/answerService/answerService.d.ts +2 -1
  57. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  58. package/cjs/src/utils/graphql/answerService/answerService.js +2 -1
  59. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
  60. package/cjs/src/utils/processData.d.ts.map +1 -1
  61. package/cjs/src/utils/processData.js +15 -0
  62. package/cjs/src/utils/processData.js.map +1 -1
  63. package/cjs/src/utils/processData.spec.js +15 -0
  64. package/cjs/src/utils/processData.spec.js.map +1 -1
  65. package/cjs/src/utils/processTrigger.d.ts.map +1 -1
  66. package/cjs/src/utils/processTrigger.js +14 -0
  67. package/cjs/src/utils/processTrigger.js.map +1 -1
  68. package/cjs/src/utils/processTrigger.spec.js +54 -0
  69. package/cjs/src/utils/processTrigger.spec.js.map +1 -1
  70. package/cjs/src/utils.d.ts +11 -2
  71. package/cjs/src/utils.d.ts.map +1 -1
  72. package/cjs/src/utils.js +70 -1
  73. package/cjs/src/utils.js.map +1 -1
  74. package/cjs/src/utils.spec.js +85 -0
  75. package/cjs/src/utils.spec.js.map +1 -1
  76. package/dist/{index-DeFzsyFF.js → index-BKIWUvTr.js} +1 -1
  77. package/dist/src/embed/app.d.ts +96 -156
  78. package/dist/src/embed/app.d.ts.map +1 -1
  79. package/dist/src/embed/bodyless-conversation.d.ts +4 -4
  80. package/dist/src/embed/bodyless-conversation.d.ts.map +1 -1
  81. package/dist/src/embed/conversation.d.ts +22 -11
  82. package/dist/src/embed/conversation.d.ts.map +1 -1
  83. package/dist/src/embed/liveboard.d.ts +110 -167
  84. package/dist/src/embed/liveboard.d.ts.map +1 -1
  85. package/dist/src/embed/sage.d.ts +17 -2
  86. package/dist/src/embed/sage.d.ts.map +1 -1
  87. package/dist/src/embed/search-bar.d.ts +16 -6
  88. package/dist/src/embed/search-bar.d.ts.map +1 -1
  89. package/dist/src/embed/search.d.ts +46 -14
  90. package/dist/src/embed/search.d.ts.map +1 -1
  91. package/dist/src/embed/ts-embed.d.ts +19 -2
  92. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  93. package/dist/src/index.d.ts +2 -2
  94. package/dist/src/index.d.ts.map +1 -1
  95. package/dist/src/react/all-types-export.d.ts +1 -1
  96. package/dist/src/react/all-types-export.d.ts.map +1 -1
  97. package/dist/src/react/index.d.ts +1 -1
  98. package/dist/src/react/index.d.ts.map +1 -1
  99. package/dist/src/react/util.d.ts +7 -4
  100. package/dist/src/react/util.d.ts.map +1 -1
  101. package/dist/src/types.d.ts +482 -251
  102. package/dist/src/types.d.ts.map +1 -1
  103. package/dist/src/utils/graphql/answerService/answerService.d.ts +2 -1
  104. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  105. package/dist/src/utils/processData.d.ts.map +1 -1
  106. package/dist/src/utils/processTrigger.d.ts.map +1 -1
  107. package/dist/src/utils.d.ts +11 -2
  108. package/dist/src/utils.d.ts.map +1 -1
  109. package/dist/tsembed-react.es.js +3477 -3311
  110. package/dist/tsembed-react.js +3476 -3310
  111. package/dist/tsembed.es.js +192 -26
  112. package/dist/tsembed.js +195 -29
  113. package/dist/visual-embed-sdk-react-full.d.ts +845 -655
  114. package/dist/visual-embed-sdk-react.d.ts +845 -655
  115. package/dist/visual-embed-sdk.d.ts +827 -640
  116. package/lib/package.json +1 -1
  117. package/lib/src/embed/app.d.ts +96 -156
  118. package/lib/src/embed/app.d.ts.map +1 -1
  119. package/lib/src/embed/app.js +6 -3
  120. package/lib/src/embed/app.js.map +1 -1
  121. package/lib/src/embed/app.spec.js +10 -0
  122. package/lib/src/embed/app.spec.js.map +1 -1
  123. package/lib/src/embed/bodyless-conversation.d.ts +4 -4
  124. package/lib/src/embed/bodyless-conversation.d.ts.map +1 -1
  125. package/lib/src/embed/bodyless-conversation.js +1 -1
  126. package/lib/src/embed/bodyless-conversation.js.map +1 -1
  127. package/lib/src/embed/conversation.d.ts +22 -11
  128. package/lib/src/embed/conversation.d.ts.map +1 -1
  129. package/lib/src/embed/conversation.js +1 -1
  130. package/lib/src/embed/conversation.js.map +1 -1
  131. package/lib/src/embed/liveboard.d.ts +110 -167
  132. package/lib/src/embed/liveboard.d.ts.map +1 -1
  133. package/lib/src/embed/liveboard.js +4 -1
  134. package/lib/src/embed/liveboard.js.map +1 -1
  135. package/lib/src/embed/liveboard.spec.js +11 -0
  136. package/lib/src/embed/liveboard.spec.js.map +1 -1
  137. package/lib/src/embed/sage.d.ts +17 -2
  138. package/lib/src/embed/sage.d.ts.map +1 -1
  139. package/lib/src/embed/sage.js +2 -0
  140. package/lib/src/embed/sage.js.map +1 -1
  141. package/lib/src/embed/search-bar.d.ts +16 -6
  142. package/lib/src/embed/search-bar.d.ts.map +1 -1
  143. package/lib/src/embed/search-bar.js.map +1 -1
  144. package/lib/src/embed/search.d.ts +46 -14
  145. package/lib/src/embed/search.d.ts.map +1 -1
  146. package/lib/src/embed/search.js.map +1 -1
  147. package/lib/src/embed/ts-embed.d.ts +19 -2
  148. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  149. package/lib/src/embed/ts-embed.js +49 -0
  150. package/lib/src/embed/ts-embed.js.map +1 -1
  151. package/lib/src/embed/ts-embed.spec.js +45 -4
  152. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  153. package/lib/src/index.d.ts +2 -2
  154. package/lib/src/index.d.ts.map +1 -1
  155. package/lib/src/index.js +2 -2
  156. package/lib/src/index.js.map +1 -1
  157. package/lib/src/react/all-types-export.d.ts +1 -1
  158. package/lib/src/react/all-types-export.d.ts.map +1 -1
  159. package/lib/src/react/all-types-export.js +1 -1
  160. package/lib/src/react/all-types-export.js.map +1 -1
  161. package/lib/src/react/index.d.ts +1 -1
  162. package/lib/src/react/index.d.ts.map +1 -1
  163. package/lib/src/react/index.js +1 -1
  164. package/lib/src/react/util.d.ts +7 -4
  165. package/lib/src/react/util.d.ts.map +1 -1
  166. package/lib/src/react/util.js.map +1 -1
  167. package/lib/src/types.d.ts +482 -251
  168. package/lib/src/types.d.ts.map +1 -1
  169. package/lib/src/types.js +31 -14
  170. package/lib/src/types.js.map +1 -1
  171. package/lib/src/utils/graphql/answerService/answerService.d.ts +2 -1
  172. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  173. package/lib/src/utils/graphql/answerService/answerService.js +2 -1
  174. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
  175. package/lib/src/utils/processData.d.ts.map +1 -1
  176. package/lib/src/utils/processData.js +15 -0
  177. package/lib/src/utils/processData.js.map +1 -1
  178. package/lib/src/utils/processData.spec.js +15 -0
  179. package/lib/src/utils/processData.spec.js.map +1 -1
  180. package/lib/src/utils/processTrigger.d.ts.map +1 -1
  181. package/lib/src/utils/processTrigger.js +14 -0
  182. package/lib/src/utils/processTrigger.js.map +1 -1
  183. package/lib/src/utils/processTrigger.spec.js +54 -0
  184. package/lib/src/utils/processTrigger.spec.js.map +1 -1
  185. package/lib/src/utils.d.ts +11 -2
  186. package/lib/src/utils.d.ts.map +1 -1
  187. package/lib/src/utils.js +67 -0
  188. package/lib/src/utils.js.map +1 -1
  189. package/lib/src/utils.spec.js +86 -1
  190. package/lib/src/utils.spec.js.map +1 -1
  191. package/lib/src/visual-embed-sdk.d.ts +836 -649
  192. package/package.json +1 -1
  193. package/src/embed/app.spec.ts +14 -0
  194. package/src/embed/app.ts +97 -152
  195. package/src/embed/bodyless-conversation.ts +4 -4
  196. package/src/embed/conversation.ts +23 -12
  197. package/src/embed/liveboard.spec.ts +15 -0
  198. package/src/embed/liveboard.ts +117 -172
  199. package/src/embed/sage.ts +17 -5
  200. package/src/embed/search-bar.tsx +16 -17
  201. package/src/embed/search.ts +47 -21
  202. package/src/embed/ts-embed.spec.ts +52 -4
  203. package/src/embed/ts-embed.ts +61 -6
  204. package/src/index.ts +2 -0
  205. package/src/react/all-types-export.ts +1 -0
  206. package/src/react/index.tsx +3 -3
  207. package/src/react/util.ts +6 -4
  208. package/src/types.ts +488 -253
  209. package/src/utils/graphql/answerService/answerService.ts +5 -4
  210. package/src/utils/processData.spec.ts +28 -0
  211. package/src/utils/processData.ts +17 -0
  212. package/src/utils/processTrigger.spec.ts +90 -0
  213. package/src/utils/processTrigger.ts +16 -1
  214. package/src/utils.spec.ts +113 -0
  215. package/src/utils.ts +78 -2
  216. package/dist/index-NZYq1Tu3.js +0 -7370
@@ -27,19 +27,20 @@ export interface UnderlyingDataPoint {
27
27
 
28
28
  /**
29
29
  * AnswerService provides a simple way to work with ThoughtSpot Answers.
30
- *
30
+ *
31
31
  * This service allows you to interact with ThoughtSpot Answers programmatically,
32
32
  * making it easy to customize visualizations, filter data, and extract insights
33
33
  * directly from your application.
34
- *
34
+ *
35
35
  * You can use this service to:
36
+ *
36
37
  * - Add or remove columns from Answers (`addColumns`, `removeColumns`, `addColumnsByName`)
37
38
  * - Apply filters to Answers (`addFilter`)
38
39
  * - Get data from Answers in different formats (JSON, CSV, PNG) (`fetchData`, `fetchCSVBlob`, `fetchPNGBlob`)
39
40
  * - Get data for specific points in visualizations (`getUnderlyingDataForPoint`)
40
41
  * - Run custom queries (`executeQuery`)
41
- * - Add visualizations to liveboards (`addDisplayedVizToLiveboard`)
42
- *
42
+ * - Add visualizations to Liveboards (`addDisplayedVizToLiveboard`)
43
+ *
43
44
  * @example
44
45
  * ```js
45
46
  * // Get the answer service
@@ -6,6 +6,8 @@ import * as base from '../embed/base';
6
6
  import * as embedConfigInstance from '../embed/embedConfig';
7
7
  import { EmbedEvent, AuthType } from '../types';
8
8
  import * as sessionInfoService from './sessionInfoService';
9
+ import * as utilsModule from '../utils';
10
+ import { logger } from './logger';
9
11
 
10
12
  describe('Unit test for process data', () => {
11
13
  beforeAll(() => {
@@ -251,4 +253,30 @@ describe('Unit test for process data', () => {
251
253
  expect(base.notifyAuthFailure).toBeCalledWith(auth.AuthFailureType.IDLE_SESSION_TIMEOUT);
252
254
  expect(el.innerHTML).toBe('Hello');
253
255
  });
256
+
257
+ test('should handle ExitPresentMode when disableFullscreenPresentation is false (enabled)', () => {
258
+ const mockConfig = {
259
+ disableFullscreenPresentation: false,
260
+ };
261
+
262
+ const mockHandleExitPresentMode = jest.spyOn(utilsModule, 'handleExitPresentMode').mockImplementation(() => {});
263
+
264
+ jest.spyOn(embedConfigInstance, 'getEmbedConfig').mockReturnValue(mockConfig);
265
+
266
+ const processedData = {
267
+ type: EmbedEvent.ExitPresentMode,
268
+ data: {},
269
+ };
270
+
271
+ processDataInstance.processEventData(
272
+ EmbedEvent.ExitPresentMode,
273
+ processedData,
274
+ thoughtSpotHost,
275
+ null,
276
+ );
277
+
278
+ expect(mockHandleExitPresentMode).toHaveBeenCalled();
279
+
280
+ mockHandleExitPresentMode.mockReset();
281
+ });
254
282
  });
@@ -10,6 +10,21 @@ import { AuthType, CustomActionPayload, EmbedEvent } from '../types';
10
10
  import { AnswerService } from './graphql/answerService/answerService';
11
11
  import { resetCachedAuthToken } from '../authToken';
12
12
  import { ERROR_MESSAGE } from '../errors';
13
+ import { logger } from '../utils/logger';
14
+ import { handleExitPresentMode } from '../utils';
15
+
16
+ /**
17
+ * Process the ExitPresentMode event and handle default fullscreen exit
18
+ * @param e - The event data
19
+ */
20
+ function processExitPresentMode(e: any) {
21
+ const embedConfig = getEmbedConfig();
22
+ const disableFullscreenPresentation = embedConfig?.disableFullscreenPresentation ?? true;
23
+
24
+ if (!disableFullscreenPresentation) {
25
+ handleExitPresentMode();
26
+ }
27
+ }
13
28
 
14
29
  /**
15
30
  *
@@ -136,6 +151,8 @@ export function processEventData(
136
151
  return processAuthFailure(e, containerEl);
137
152
  case EmbedEvent.AuthLogout:
138
153
  return processAuthLogout(e, containerEl);
154
+ case EmbedEvent.ExitPresentMode:
155
+ return processExitPresentMode(e);
139
156
  default:
140
157
  }
141
158
  return e;
@@ -1,6 +1,9 @@
1
1
  import * as _processTriggerInstance from './processTrigger';
2
2
  import { HostEvent } from '../types';
3
3
  import { messageChannelMock, mockMessageChannel } from '../test/test-utils';
4
+ import { logger } from './logger';
5
+ import * as utilsModule from '../utils';
6
+ import * as embedConfigModule from '../embed/embedConfig';
4
7
 
5
8
  describe('Unit test for processTrigger', () => {
6
9
  const iFrame: any = {
@@ -8,6 +11,11 @@ describe('Unit test for processTrigger', () => {
8
11
  postMessage: jest.fn(),
9
12
  },
10
13
  };
14
+
15
+ beforeEach(() => {
16
+ jest.clearAllMocks();
17
+ });
18
+
11
19
  test('when hostevent is reload, reload function should be called with iFrame', async () => {
12
20
  jest.useFakeTimers();
13
21
  const iFrameElement = document.createElement('iframe');
@@ -86,4 +94,86 @@ describe('Unit test for processTrigger', () => {
86
94
  expect(messageChannelMock.port1.close).toBeCalled();
87
95
  await expect(triggerPromise).resolves.toBeInstanceOf(Error);
88
96
  });
97
+
98
+ describe('Present event with fullscreen presentation flag', () => {
99
+ let mockHandlePresentEvent: any;
100
+ let mockLoggerWarn: any;
101
+ let mockGetEmbedConfig: any;
102
+
103
+ beforeEach(() => {
104
+ mockHandlePresentEvent = jest.spyOn(utilsModule, 'handlePresentEvent').mockImplementation(() => {});
105
+ mockLoggerWarn = jest.spyOn(logger, 'warn').mockImplementation(() => {});
106
+ mockGetEmbedConfig = jest.spyOn(embedConfigModule, 'getEmbedConfig').mockImplementation(() => ({}));
107
+ });
108
+
109
+ afterEach(() => {
110
+ mockHandlePresentEvent.mockReset();
111
+ mockLoggerWarn.mockReset();
112
+ mockGetEmbedConfig.mockReset();
113
+ });
114
+
115
+ test('should handle Present event when disableFullscreenPresentation is false (enabled)', () => {
116
+ const mockConfig = {
117
+ disableFullscreenPresentation: false,
118
+ };
119
+ mockGetEmbedConfig.mockReturnValue(mockConfig);
120
+
121
+ const messageType = HostEvent.Present;
122
+ const thoughtSpotHost = 'https://example.thoughtspot.com';
123
+ const data = {};
124
+
125
+ _processTriggerInstance.processTrigger(
126
+ iFrame,
127
+ messageType,
128
+ thoughtSpotHost,
129
+ data,
130
+ );
131
+
132
+ expect(mockHandlePresentEvent).toHaveBeenCalledWith(iFrame);
133
+ });
134
+
135
+ test('should warn and not handle Present event when disableFullscreenPresentation is true (disabled)', () => {
136
+ const mockConfig = {
137
+ disableFullscreenPresentation: true,
138
+ };
139
+ mockGetEmbedConfig.mockReturnValue(mockConfig);
140
+
141
+ const messageType = HostEvent.Present;
142
+ const thoughtSpotHost = 'https://example.thoughtspot.com';
143
+ const data = {};
144
+
145
+ _processTriggerInstance.processTrigger(
146
+ iFrame,
147
+ messageType,
148
+ thoughtSpotHost,
149
+ data,
150
+ );
151
+
152
+ expect(mockHandlePresentEvent).not.toHaveBeenCalled();
153
+ expect(mockLoggerWarn).toHaveBeenCalledWith(
154
+ 'Fullscreen presentation mode is disabled. Set disableFullscreenPresentation: false to enable this feature.',
155
+ );
156
+ });
157
+
158
+ test('should default to disabled when disableFullscreenPresentation is not provided', () => {
159
+ const mockConfig = {};
160
+ mockGetEmbedConfig.mockReturnValue(mockConfig);
161
+
162
+ const messageType = HostEvent.Present;
163
+ const thoughtSpotHost = 'https://example.thoughtspot.com';
164
+ const data = {};
165
+
166
+ _processTriggerInstance.processTrigger(
167
+ iFrame,
168
+ messageType,
169
+ thoughtSpotHost,
170
+ data,
171
+ );
172
+
173
+ expect(mockHandlePresentEvent).not.toHaveBeenCalled();
174
+ expect(mockLoggerWarn).toHaveBeenCalledWith(
175
+ 'Fullscreen presentation mode is disabled. Set disableFullscreenPresentation: false to enable this feature.',
176
+ );
177
+ });
178
+ });
89
179
  });
@@ -1,5 +1,8 @@
1
1
  import { ERROR_MESSAGE } from '../errors';
2
- import { HostEvent } from '../types';
2
+ import { HostEvent, MessagePayload } from '../types';
3
+ import { logger } from '../utils/logger';
4
+ import { handlePresentEvent } from '../utils';
5
+ import { getEmbedConfig } from '../embed/embedConfig';
3
6
 
4
7
  /**
5
8
  * Reloads the ThoughtSpot iframe.
@@ -51,6 +54,18 @@ export function processTrigger(
51
54
  reload(iFrame);
52
55
  return res(null);
53
56
  }
57
+
58
+ if (messageType === HostEvent.Present) {
59
+ const embedConfig = getEmbedConfig();
60
+ const disableFullscreenPresentation = embedConfig?.disableFullscreenPresentation ?? true;
61
+
62
+ if (!disableFullscreenPresentation) {
63
+ handlePresentEvent(iFrame);
64
+ } else {
65
+ logger.warn('Fullscreen presentation mode is disabled. Set disableFullscreenPresentation: false to enable this feature.');
66
+ }
67
+ }
68
+
54
69
  const channel = new MessageChannel();
55
70
  channel.port1.onmessage = ({ data: responseData }) => {
56
71
  channel.port1.close();
package/src/utils.spec.ts CHANGED
@@ -13,8 +13,19 @@ import {
13
13
  isUndefined,
14
14
  storeValueInWindow,
15
15
  getValueFromWindow,
16
+ handlePresentEvent,
17
+ handleExitPresentMode,
16
18
  } from './utils';
17
19
  import { RuntimeFilterOp } from './types';
20
+ import { logger } from './utils/logger';
21
+
22
+ // Mock logger
23
+ jest.mock('./utils/logger', () => ({
24
+ logger: {
25
+ warn: jest.fn(),
26
+ error: jest.fn(),
27
+ },
28
+ }));
18
29
 
19
30
  describe('unit test for utils', () => {
20
31
  test('getQueryParamString', () => {
@@ -294,3 +305,105 @@ describe('unit test for utils', () => {
294
305
  });
295
306
  });
296
307
  });
308
+
309
+ describe('Fullscreen Utility Functions', () => {
310
+ let originalExitFullscreen: any;
311
+ let mockIframe: HTMLIFrameElement;
312
+
313
+ beforeEach(() => {
314
+ jest.clearAllMocks();
315
+
316
+ // Store and mock exitFullscreen
317
+ originalExitFullscreen = document.exitFullscreen;
318
+ document.exitFullscreen = jest.fn();
319
+
320
+ // Mock iframe
321
+ mockIframe = {
322
+ requestFullscreen: jest.fn(),
323
+ } as any;
324
+
325
+ // Mock not in fullscreen initially
326
+ Object.defineProperty(document, 'fullscreenElement', {
327
+ writable: true,
328
+ value: null,
329
+ });
330
+ });
331
+
332
+ afterEach(() => {
333
+ // Restore original method
334
+ document.exitFullscreen = originalExitFullscreen;
335
+ });
336
+
337
+ describe('handlePresentEvent', () => {
338
+ it('should enter fullscreen when iframe is provided', () => {
339
+ const mockPromise = Promise.resolve();
340
+ (mockIframe.requestFullscreen as jest.Mock).mockReturnValue(mockPromise);
341
+
342
+ handlePresentEvent(mockIframe);
343
+
344
+ expect(mockIframe.requestFullscreen).toHaveBeenCalled();
345
+ expect(logger.error).not.toHaveBeenCalled();
346
+ });
347
+
348
+ it('should log error when fullscreen API is not supported', () => {
349
+ delete (mockIframe as any).requestFullscreen;
350
+
351
+ handlePresentEvent(mockIframe);
352
+
353
+ expect(logger.error).toHaveBeenCalledWith('Fullscreen API is not supported by this browser.');
354
+ });
355
+
356
+ it('should not attempt fullscreen when already in fullscreen mode', () => {
357
+ Object.defineProperty(document, 'fullscreenElement', {
358
+ writable: true,
359
+ value: mockIframe,
360
+ });
361
+
362
+ handlePresentEvent(mockIframe);
363
+
364
+ expect(mockIframe.requestFullscreen).not.toHaveBeenCalled();
365
+ expect(logger.error).not.toHaveBeenCalled();
366
+ });
367
+ });
368
+
369
+ describe('handleExitPresentMode', () => {
370
+ beforeEach(() => {
371
+ // Mock being in fullscreen
372
+ Object.defineProperty(document, 'fullscreenElement', {
373
+ writable: true,
374
+ value: document.createElement('iframe'),
375
+ });
376
+ });
377
+
378
+ it('should exit fullscreen when in fullscreen mode', () => {
379
+ const mockPromise = Promise.resolve();
380
+ (document.exitFullscreen as jest.Mock).mockReturnValue(mockPromise);
381
+
382
+ handleExitPresentMode();
383
+
384
+ expect(document.exitFullscreen).toHaveBeenCalled();
385
+ expect(logger.warn).not.toHaveBeenCalled();
386
+ });
387
+
388
+ it('should not attempt to exit when not in fullscreen mode', () => {
389
+ Object.defineProperty(document, 'fullscreenElement', {
390
+ writable: true,
391
+ value: null,
392
+ });
393
+
394
+ handleExitPresentMode();
395
+
396
+ expect(document.exitFullscreen).not.toHaveBeenCalled();
397
+ expect(logger.warn).not.toHaveBeenCalled();
398
+ });
399
+
400
+ it('should log warning when exit fullscreen API is not supported', () => {
401
+ // Mock being in fullscreen but no exit methods available
402
+ document.exitFullscreen = undefined as any;
403
+
404
+ handleExitPresentMode();
405
+
406
+ expect(logger.warn).toHaveBeenCalledWith('Exit fullscreen API is not supported by this browser.');
407
+ });
408
+ });
409
+ });
package/src/utils.ts CHANGED
@@ -13,9 +13,10 @@ import {
13
13
  RuntimeFilter,
14
14
  CustomisationsInterface,
15
15
  DOMSelector,
16
- ViewConfig,
17
16
  RuntimeParameter,
17
+ AllEmbedViewConfig,
18
18
  } from './types';
19
+ import { logger } from './utils/logger';
19
20
 
20
21
  /**
21
22
  * Construct a runtime filters query string from the given filters.
@@ -216,7 +217,7 @@ export const checkReleaseVersionInBeta = (
216
217
 
217
218
  export const getCustomisations = (
218
219
  embedConfig: EmbedConfig,
219
- viewConfig: ViewConfig,
220
+ viewConfig: AllEmbedViewConfig,
220
221
  ): CustomisationsInterface => {
221
222
  const customizationsFromViewConfig = viewConfig.customizations;
222
223
  const customizationsFromEmbedConfig = embedConfig.customizations
@@ -387,3 +388,78 @@ export function resetValueFromWindow(key: string): boolean {
387
388
  }
388
389
  return false;
389
390
  }
391
+
392
+ /**
393
+ * Check if the document is currently in fullscreen mode
394
+ */
395
+ const isInFullscreen = (): boolean => {
396
+ return !!(
397
+ document.fullscreenElement ||
398
+ (document as any).webkitFullscreenElement ||
399
+ (document as any).mozFullScreenElement ||
400
+ (document as any).msFullscreenElement
401
+ );
402
+ };
403
+
404
+ /**
405
+ * Handle Present HostEvent by entering fullscreen mode
406
+ * @param iframe The iframe element to make fullscreen
407
+ */
408
+ export const handlePresentEvent = async (iframe: HTMLIFrameElement): Promise<void> => {
409
+ if (isInFullscreen()) {
410
+ return; // Already in fullscreen
411
+ }
412
+
413
+ // Browser-specific methods to enter fullscreen mode
414
+ const fullscreenMethods = [
415
+ 'requestFullscreen', // Standard API
416
+ 'webkitRequestFullscreen', // WebKit browsers
417
+ 'mozRequestFullScreen', // Firefox
418
+ 'msRequestFullscreen' // IE/Edge
419
+ ];
420
+
421
+ for (const method of fullscreenMethods) {
422
+ if (typeof (iframe as any)[method] === 'function') {
423
+ try {
424
+ const result = (iframe as any)[method]();
425
+ await Promise.resolve(result);
426
+ return;
427
+ } catch (error) {
428
+ logger.warn(`Failed to enter fullscreen using ${method}:`, error);
429
+ }
430
+ }
431
+ }
432
+
433
+ logger.error('Fullscreen API is not supported by this browser.');
434
+ };
435
+
436
+ /**
437
+ * Handle ExitPresentMode EmbedEvent by exiting fullscreen mode
438
+ */
439
+ export const handleExitPresentMode = async (): Promise<void> => {
440
+ if (!isInFullscreen()) {
441
+ return; // Not in fullscreen
442
+ }
443
+
444
+ const exitFullscreenMethods = [
445
+ 'exitFullscreen', // Standard API
446
+ 'webkitExitFullscreen', // WebKit browsers
447
+ 'mozCancelFullScreen', // Firefox
448
+ 'msExitFullscreen' // IE/Edge
449
+ ];
450
+
451
+ // Try each method until one works
452
+ for (const method of exitFullscreenMethods) {
453
+ if (typeof (document as any)[method] === 'function') {
454
+ try {
455
+ const result = (document as any)[method]();
456
+ await Promise.resolve(result);
457
+ return;
458
+ } catch (error) {
459
+ logger.warn(`Failed to exit fullscreen using ${method}:`, error);
460
+ }
461
+ }
462
+ }
463
+
464
+ logger.warn('Exit fullscreen API is not supported by this browser.');
465
+ };