@thoughtspot/visual-embed-sdk 1.50.1 → 1.51.0-test

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 (238) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/config.d.ts +1 -0
  3. package/cjs/src/config.d.ts.map +1 -1
  4. package/cjs/src/config.js +2 -1
  5. package/cjs/src/config.js.map +1 -1
  6. package/cjs/src/css-variables.d.ts +63 -0
  7. package/cjs/src/css-variables.d.ts.map +1 -1
  8. package/cjs/src/embed/app.d.ts +148 -25
  9. package/cjs/src/embed/app.d.ts.map +1 -1
  10. package/cjs/src/embed/app.js +74 -37
  11. package/cjs/src/embed/app.js.map +1 -1
  12. package/cjs/src/embed/app.spec.js +571 -150
  13. package/cjs/src/embed/app.spec.js.map +1 -1
  14. package/cjs/src/embed/base.d.ts +1 -1
  15. package/cjs/src/embed/base.js +1 -1
  16. package/cjs/src/embed/conversation.d.ts +375 -2
  17. package/cjs/src/embed/conversation.d.ts.map +1 -1
  18. package/cjs/src/embed/conversation.js +21 -15
  19. package/cjs/src/embed/conversation.js.map +1 -1
  20. package/cjs/src/embed/conversation.spec.js +323 -17
  21. package/cjs/src/embed/conversation.spec.js.map +1 -1
  22. package/cjs/src/embed/events.spec.js +45 -0
  23. package/cjs/src/embed/events.spec.js.map +1 -1
  24. package/cjs/src/embed/host-events.spec.js +81 -0
  25. package/cjs/src/embed/host-events.spec.js.map +1 -1
  26. package/cjs/src/embed/hostEventClient/contracts.d.ts +15 -0
  27. package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  28. package/cjs/src/embed/hostEventClient/contracts.js +1 -0
  29. package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
  30. package/cjs/src/embed/hostEventClient/host-event-client.d.ts +1 -1
  31. package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  32. package/cjs/src/embed/hostEventClient/host-event-client.js +1 -0
  33. package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
  34. package/cjs/src/embed/hostEventClient/host-event-client.spec.js +27 -0
  35. package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  36. package/cjs/src/embed/liveboard.d.ts +76 -14
  37. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  38. package/cjs/src/embed/liveboard.js +50 -9
  39. package/cjs/src/embed/liveboard.js.map +1 -1
  40. package/cjs/src/embed/liveboard.spec.js +432 -4
  41. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  42. package/cjs/src/embed/spotter-utils.d.ts +15 -1
  43. package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
  44. package/cjs/src/embed/spotter-utils.js +28 -1
  45. package/cjs/src/embed/spotter-utils.js.map +1 -1
  46. package/cjs/src/embed/spotter-utils.spec.js +129 -0
  47. package/cjs/src/embed/spotter-utils.spec.js.map +1 -1
  48. package/cjs/src/embed/spotter-viz-utils.d.ts +9 -10
  49. package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -1
  50. package/cjs/src/embed/spotter-viz-utils.js.map +1 -1
  51. package/cjs/src/embed/ts-embed.d.ts +16 -8
  52. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  53. package/cjs/src/embed/ts-embed.js +82 -30
  54. package/cjs/src/embed/ts-embed.js.map +1 -1
  55. package/cjs/src/embed/ts-embed.spec.js +537 -3
  56. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  57. package/cjs/src/index.d.ts +3 -3
  58. package/cjs/src/index.d.ts.map +1 -1
  59. package/cjs/src/index.js +3 -2
  60. package/cjs/src/index.js.map +1 -1
  61. package/cjs/src/mixpanel-service.d.ts +4 -0
  62. package/cjs/src/mixpanel-service.d.ts.map +1 -1
  63. package/cjs/src/mixpanel-service.js +4 -0
  64. package/cjs/src/mixpanel-service.js.map +1 -1
  65. package/cjs/src/react/all-types-export.d.ts +1 -1
  66. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  67. package/cjs/src/react/all-types-export.js +2 -1
  68. package/cjs/src/react/all-types-export.js.map +1 -1
  69. package/cjs/src/react/all-types-export.parity.spec.d.ts +2 -0
  70. package/cjs/src/react/all-types-export.parity.spec.d.ts.map +1 -0
  71. package/cjs/src/react/all-types-export.parity.spec.js +194 -0
  72. package/cjs/src/react/all-types-export.parity.spec.js.map +1 -0
  73. package/cjs/src/react/index.d.ts +66 -32
  74. package/cjs/src/react/index.d.ts.map +1 -1
  75. package/cjs/src/react/index.js +5 -3
  76. package/cjs/src/react/index.js.map +1 -1
  77. package/cjs/src/react/index.spec.js +101 -0
  78. package/cjs/src/react/index.spec.js.map +1 -1
  79. package/cjs/src/types.d.ts +789 -32
  80. package/cjs/src/types.d.ts.map +1 -1
  81. package/cjs/src/types.js +610 -20
  82. package/cjs/src/types.js.map +1 -1
  83. package/cjs/src/utils.spec.js +4 -0
  84. package/cjs/src/utils.spec.js.map +1 -1
  85. package/dist/{index-fCne7kmU.js → index-Bivg-mDx.js} +1 -1
  86. package/dist/src/config.d.ts +1 -0
  87. package/dist/src/config.d.ts.map +1 -1
  88. package/dist/src/css-variables.d.ts +63 -0
  89. package/dist/src/css-variables.d.ts.map +1 -1
  90. package/dist/src/embed/app.d.ts +148 -25
  91. package/dist/src/embed/app.d.ts.map +1 -1
  92. package/dist/src/embed/base.d.ts +1 -1
  93. package/dist/src/embed/conversation.d.ts +375 -2
  94. package/dist/src/embed/conversation.d.ts.map +1 -1
  95. package/dist/src/embed/hostEventClient/contracts.d.ts +15 -0
  96. package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  97. package/dist/src/embed/hostEventClient/host-event-client.d.ts +1 -1
  98. package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  99. package/dist/src/embed/liveboard.d.ts +76 -14
  100. package/dist/src/embed/liveboard.d.ts.map +1 -1
  101. package/dist/src/embed/spotter-utils.d.ts +15 -1
  102. package/dist/src/embed/spotter-utils.d.ts.map +1 -1
  103. package/dist/src/embed/spotter-viz-utils.d.ts +9 -10
  104. package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -1
  105. package/dist/src/embed/ts-embed.d.ts +16 -8
  106. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  107. package/dist/src/index.d.ts +3 -3
  108. package/dist/src/index.d.ts.map +1 -1
  109. package/dist/src/mixpanel-service.d.ts +4 -0
  110. package/dist/src/mixpanel-service.d.ts.map +1 -1
  111. package/dist/src/react/all-types-export.d.ts +1 -1
  112. package/dist/src/react/all-types-export.d.ts.map +1 -1
  113. package/dist/src/react/all-types-export.parity.spec.d.ts +2 -0
  114. package/dist/src/react/all-types-export.parity.spec.d.ts.map +1 -0
  115. package/dist/src/react/index.d.ts +66 -32
  116. package/dist/src/react/index.d.ts.map +1 -1
  117. package/dist/src/types.d.ts +789 -32
  118. package/dist/src/types.d.ts.map +1 -1
  119. package/dist/tsembed-react.es.js +878 -120
  120. package/dist/tsembed-react.js +877 -119
  121. package/dist/tsembed.es.js +936 -181
  122. package/dist/tsembed.js +938 -183
  123. package/dist/visual-embed-sdk-react-full.d.ts +1553 -128
  124. package/dist/visual-embed-sdk-react.d.ts +1555 -129
  125. package/dist/visual-embed-sdk.d.ts +1499 -100
  126. package/lib/package.json +1 -1
  127. package/lib/src/config.d.ts +1 -0
  128. package/lib/src/config.d.ts.map +1 -1
  129. package/lib/src/config.js +1 -0
  130. package/lib/src/config.js.map +1 -1
  131. package/lib/src/css-variables.d.ts +63 -0
  132. package/lib/src/css-variables.d.ts.map +1 -1
  133. package/lib/src/embed/app.d.ts +148 -25
  134. package/lib/src/embed/app.d.ts.map +1 -1
  135. package/lib/src/embed/app.js +75 -38
  136. package/lib/src/embed/app.js.map +1 -1
  137. package/lib/src/embed/app.spec.js +572 -151
  138. package/lib/src/embed/app.spec.js.map +1 -1
  139. package/lib/src/embed/base.d.ts +1 -1
  140. package/lib/src/embed/base.js +1 -1
  141. package/lib/src/embed/conversation.d.ts +375 -2
  142. package/lib/src/embed/conversation.d.ts.map +1 -1
  143. package/lib/src/embed/conversation.js +23 -17
  144. package/lib/src/embed/conversation.js.map +1 -1
  145. package/lib/src/embed/conversation.spec.js +323 -17
  146. package/lib/src/embed/conversation.spec.js.map +1 -1
  147. package/lib/src/embed/events.spec.js +45 -0
  148. package/lib/src/embed/events.spec.js.map +1 -1
  149. package/lib/src/embed/host-events.spec.js +81 -0
  150. package/lib/src/embed/host-events.spec.js.map +1 -1
  151. package/lib/src/embed/hostEventClient/contracts.d.ts +15 -0
  152. package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  153. package/lib/src/embed/hostEventClient/contracts.js +1 -0
  154. package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
  155. package/lib/src/embed/hostEventClient/host-event-client.d.ts +1 -1
  156. package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  157. package/lib/src/embed/hostEventClient/host-event-client.js +1 -0
  158. package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
  159. package/lib/src/embed/hostEventClient/host-event-client.spec.js +27 -0
  160. package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  161. package/lib/src/embed/liveboard.d.ts +76 -14
  162. package/lib/src/embed/liveboard.d.ts.map +1 -1
  163. package/lib/src/embed/liveboard.js +50 -9
  164. package/lib/src/embed/liveboard.js.map +1 -1
  165. package/lib/src/embed/liveboard.spec.js +432 -4
  166. package/lib/src/embed/liveboard.spec.js.map +1 -1
  167. package/lib/src/embed/spotter-utils.d.ts +15 -1
  168. package/lib/src/embed/spotter-utils.d.ts.map +1 -1
  169. package/lib/src/embed/spotter-utils.js +25 -0
  170. package/lib/src/embed/spotter-utils.js.map +1 -1
  171. package/lib/src/embed/spotter-utils.spec.js +130 -1
  172. package/lib/src/embed/spotter-utils.spec.js.map +1 -1
  173. package/lib/src/embed/spotter-viz-utils.d.ts +9 -10
  174. package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -1
  175. package/lib/src/embed/spotter-viz-utils.js.map +1 -1
  176. package/lib/src/embed/ts-embed.d.ts +16 -8
  177. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  178. package/lib/src/embed/ts-embed.js +82 -30
  179. package/lib/src/embed/ts-embed.js.map +1 -1
  180. package/lib/src/embed/ts-embed.spec.js +537 -3
  181. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  182. package/lib/src/index.d.ts +3 -3
  183. package/lib/src/index.d.ts.map +1 -1
  184. package/lib/src/index.js +2 -2
  185. package/lib/src/index.js.map +1 -1
  186. package/lib/src/mixpanel-service.d.ts +4 -0
  187. package/lib/src/mixpanel-service.d.ts.map +1 -1
  188. package/lib/src/mixpanel-service.js +4 -0
  189. package/lib/src/mixpanel-service.js.map +1 -1
  190. package/lib/src/react/all-types-export.d.ts +1 -1
  191. package/lib/src/react/all-types-export.d.ts.map +1 -1
  192. package/lib/src/react/all-types-export.js +1 -1
  193. package/lib/src/react/all-types-export.js.map +1 -1
  194. package/lib/src/react/all-types-export.parity.spec.d.ts +2 -0
  195. package/lib/src/react/all-types-export.parity.spec.d.ts.map +1 -0
  196. package/lib/src/react/all-types-export.parity.spec.js +191 -0
  197. package/lib/src/react/all-types-export.parity.spec.js.map +1 -0
  198. package/lib/src/react/index.d.ts +66 -32
  199. package/lib/src/react/index.d.ts.map +1 -1
  200. package/lib/src/react/index.js +5 -3
  201. package/lib/src/react/index.js.map +1 -1
  202. package/lib/src/react/index.spec.js +102 -1
  203. package/lib/src/react/index.spec.js.map +1 -1
  204. package/lib/src/types.d.ts +789 -32
  205. package/lib/src/types.d.ts.map +1 -1
  206. package/lib/src/types.js +610 -20
  207. package/lib/src/types.js.map +1 -1
  208. package/lib/src/utils.spec.js +4 -0
  209. package/lib/src/utils.spec.js.map +1 -1
  210. package/lib/src/visual-embed-sdk.d.ts +1499 -100
  211. package/package.json +1 -1
  212. package/src/config.ts +1 -0
  213. package/src/css-variables.ts +77 -0
  214. package/src/embed/app.spec.ts +729 -188
  215. package/src/embed/app.ts +240 -75
  216. package/src/embed/base.ts +1 -1
  217. package/src/embed/conversation.spec.ts +379 -20
  218. package/src/embed/conversation.ts +412 -18
  219. package/src/embed/events.spec.ts +56 -0
  220. package/src/embed/host-events.spec.ts +118 -0
  221. package/src/embed/hostEventClient/contracts.ts +16 -0
  222. package/src/embed/hostEventClient/host-event-client.spec.ts +46 -0
  223. package/src/embed/hostEventClient/host-event-client.ts +3 -2
  224. package/src/embed/liveboard.spec.ts +565 -4
  225. package/src/embed/liveboard.ts +150 -29
  226. package/src/embed/spotter-utils.spec.ts +140 -1
  227. package/src/embed/spotter-utils.ts +36 -1
  228. package/src/embed/spotter-viz-utils.ts +9 -10
  229. package/src/embed/ts-embed.spec.ts +699 -3
  230. package/src/embed/ts-embed.ts +99 -35
  231. package/src/index.ts +44 -2
  232. package/src/mixpanel-service.ts +4 -0
  233. package/src/react/all-types-export.parity.spec.ts +208 -0
  234. package/src/react/all-types-export.ts +22 -0
  235. package/src/react/index.spec.tsx +158 -0
  236. package/src/react/index.tsx +70 -33
  237. package/src/types.ts +791 -30
  238. package/src/utils.spec.ts +5 -0
@@ -10,6 +10,7 @@ import isEqual from 'lodash/isEqual';
10
10
  import isEmpty from 'lodash/isEmpty';
11
11
  import isObject from 'lodash/isObject';
12
12
  import {
13
+ HostEventRequest,
13
14
  TriggerPayload,
14
15
  TriggerResponse,
15
16
  UIPassthroughArrayResponse,
@@ -66,6 +67,8 @@ import {
66
67
  MessagePayload,
67
68
  ContextType,
68
69
  ContextObject,
70
+ PreRenderConfig,
71
+ BaseViewConfig,
69
72
  } from '../types';
70
73
  import { uploadMixpanelEvent, MIXPANEL_EVENT } from '../mixpanel-service';
71
74
  import { processEventData, processAuthFailure } from '../utils/processData';
@@ -206,7 +209,7 @@ export class TsEmbed {
206
209
 
207
210
  private resizeObserver: ResizeObserver;
208
211
 
209
- private preRenderContainerEl: HTMLElement | null = null;
212
+ private preRenderContainerEl: HTMLElement = document.body;
210
213
 
211
214
  private containerScrollListener: (() => void) | null = null;
212
215
 
@@ -959,11 +962,27 @@ export class TsEmbed {
959
962
  return iFrame;
960
963
  }
961
964
 
965
+ /**
966
+ * Returns a merged {@link PreRenderConfig} object where each shared key
967
+ * prefers `preRenderConfig.key` over the top-level `viewConfig.key` for
968
+ * backward compatibility.
969
+ */
970
+ protected getPreRenderConfig(): PreRenderConfig {
971
+ const viewCfg = this.viewConfig as BaseViewConfig;
972
+ const preRenderCfg = viewCfg.preRenderConfig ?? {};
973
+ return {
974
+ ...preRenderCfg,
975
+ preRenderId: preRenderCfg.preRenderId ?? viewCfg.preRenderId,
976
+ preRenderContainer: preRenderCfg.preRenderContainer ?? viewCfg.preRenderContainer,
977
+ doNotTrackPreRenderSize: preRenderCfg.doNotTrackPreRenderSize ?? viewCfg.doNotTrackPreRenderSize,
978
+ };
979
+ }
980
+
962
981
  /**
963
982
  * Returns true if this embed instance is configured for pre-rendering.
964
983
  */
965
984
  protected isPreRenderEmbed() {
966
- return !!this.viewConfig.preRenderId;
985
+ return !!this.getPreRenderConfig().preRenderId;
967
986
  }
968
987
  protected handleInsertionIntoDOM(child: string | Node): void {
969
988
  if (this.isPreRenderEmbed()) {
@@ -1119,6 +1138,7 @@ export class TsEmbed {
1119
1138
  this.setIframeElement(this.preRenderChild);
1120
1139
  }
1121
1140
  this.isRendered = true;
1141
+ this.inheritPreRenderContainer();
1122
1142
  }
1123
1143
 
1124
1144
  return this.isPreRenderConnected();
@@ -1176,7 +1196,7 @@ export class TsEmbed {
1176
1196
  * fresh element; an element passed directly cannot be re-resolved.
1177
1197
  */
1178
1198
  private resolvePreRenderContainerTarget(): HTMLElement {
1179
- const containerConfig = this.viewConfig.preRenderContainer;
1199
+ const containerConfig = this.getPreRenderConfig().preRenderContainer;
1180
1200
  let container: Element | null = null;
1181
1201
  if (typeof containerConfig === 'string') {
1182
1202
  try {
@@ -1193,15 +1213,40 @@ export class TsEmbed {
1193
1213
  return (container as HTMLElement) ?? document.body;
1194
1214
  }
1195
1215
 
1216
+ private inheritPreRenderContainer(): void {
1217
+ const preRenderedObject = this.getPreRenderObj<TsEmbed>();
1218
+ if (!preRenderedObject || preRenderedObject === (this as TsEmbed)) {
1219
+ return;
1220
+ }
1221
+ const ownerContainer = preRenderedObject.preRenderContainerEl ?? document.body;
1222
+ if (
1223
+ this.getPreRenderConfig().preRenderContainer
1224
+ && this.resolvePreRenderContainerTarget() !== ownerContainer
1225
+ ) {
1226
+ logger.warn(
1227
+ 'preRenderContainer is applied only by the component that creates the preRender; '
1228
+ + 'the one passed here is ignored. Set it on the PreRender component instead.',
1229
+ );
1230
+ }
1231
+ this.preRenderContainerEl = ownerContainer;
1232
+ this.applyPreRenderContainerPositioning();
1233
+ }
1234
+
1235
+ private getCustomPreRenderContainer(): HTMLElement | null {
1236
+ const container = this.preRenderContainerEl;
1237
+ return container && container !== document.body ? container : null;
1238
+ }
1239
+
1196
1240
  /**
1197
- * Makes the container a positioning context for the absolutely positioned
1198
- * wrapper, stashing the original inline `position` on the element (once) so
1199
- * destroy() can restore it exactly, leaving no trace. Recording it on the
1200
- * element rather than per-instance lets the override be reverted even when
1201
- * embeds share the same container.
1241
+ * Makes the resolved container a positioning context for the absolutely
1242
+ * positioned wrapper, stashing the original inline `position` on the element
1243
+ * (once) so destroy() can restore it exactly, leaving no trace. Recording it
1244
+ * on the element rather than per-instance lets the override be reverted even
1245
+ * when embeds share the same container.
1202
1246
  */
1203
- private applyPreRenderContainerPositioning(container: HTMLElement): void {
1204
- if (container === document.body) {
1247
+ private applyPreRenderContainerPositioning(): void {
1248
+ const container = this.getCustomPreRenderContainer();
1249
+ if (!container) {
1205
1250
  return;
1206
1251
  }
1207
1252
  const pos = window.getComputedStyle(container).position;
@@ -1247,11 +1292,11 @@ export class TsEmbed {
1247
1292
  resolved.addEventListener('scroll', this.containerScrollListener);
1248
1293
  }
1249
1294
  }
1250
- this.applyPreRenderContainerPositioning(resolved);
1295
+ this.preRenderContainerEl = resolved;
1296
+ this.applyPreRenderContainerPositioning();
1251
1297
  if (wrapper.parentNode !== resolved) {
1252
1298
  resolved.appendChild(wrapper);
1253
1299
  }
1254
- this.preRenderContainerEl = resolved;
1255
1300
  }
1256
1301
 
1257
1302
  protected insertIntoDOMForPreRender(child: string | Node): void {
@@ -1279,7 +1324,7 @@ export class TsEmbed {
1279
1324
 
1280
1325
  const targetContainer = this.resolvePreRenderContainerTarget();
1281
1326
  this.preRenderContainerEl = targetContainer;
1282
- this.applyPreRenderContainerPositioning(targetContainer);
1327
+ this.applyPreRenderContainerPositioning();
1283
1328
  targetContainer.appendChild(preRenderWrapper);
1284
1329
  }
1285
1330
 
@@ -1625,7 +1670,11 @@ export class TsEmbed {
1625
1670
  * ```
1626
1671
  * @version SDK: 1.45.2 | ThoughtSpot: 26.3.0.cl (for context parameter)
1627
1672
  */
1628
- public async trigger<HostEventT extends HostEvent, PayloadT, ContextT extends ContextType>(
1673
+ public async trigger<
1674
+ HostEventT extends HostEvent,
1675
+ PayloadT = HostEventRequest<HostEventT>,
1676
+ ContextT extends ContextType = ContextType,
1677
+ >(
1629
1678
  messageType: HostEventT,
1630
1679
  data: TriggerPayload<PayloadT, HostEventT> = {} as any,
1631
1680
  context?: ContextT,
@@ -1710,6 +1759,9 @@ export class TsEmbed {
1710
1759
  * @param args
1711
1760
  */
1712
1761
  public async render(): Promise<TsEmbed> {
1762
+ uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_RENDER_CALLED, {
1763
+ embedComponentType: this.viewConfig.embedComponentType,
1764
+ });
1713
1765
  if (!getIsInitCalled()) {
1714
1766
  logger.error(ERROR_MESSAGE.RENDER_CALLED_BEFORE_INIT);
1715
1767
  }
@@ -1790,7 +1842,11 @@ export class TsEmbed {
1790
1842
  showPreRenderByDefault = false,
1791
1843
  replaceExistingPreRender = false,
1792
1844
  ): Promise<TsEmbed> {
1793
- if (!this.viewConfig.preRenderId) {
1845
+ uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_PRE_RENDER, {
1846
+ showPreRenderByDefault,
1847
+ replaceExistingPreRender,
1848
+ });
1849
+ if (!this.getPreRenderConfig().preRenderId) {
1794
1850
  logger.error(ERROR_MESSAGE.PRERENDER_ID_MISSING);
1795
1851
  return this;
1796
1852
  }
@@ -1849,13 +1905,13 @@ export class TsEmbed {
1849
1905
  * same container — a shared container still needs the positioning context.
1850
1906
  */
1851
1907
  private restorePreRenderContainerPosition(): void {
1852
- const container = this.preRenderContainerEl as HTMLElement | null;
1908
+ const container = this.preRenderContainerEl;
1853
1909
  if (!container || container === document.body) {
1854
1910
  return;
1855
1911
  }
1856
1912
  // Drop our reference up front so a destroyed embed never pins a
1857
1913
  // detached container in memory; restoration uses the local handle.
1858
- this.preRenderContainerEl = null;
1914
+ this.preRenderContainerEl = document.body;
1859
1915
  const originalPosition = container.dataset[PRERENDER_CONTAINER_ORIGINAL_POSITION_KEY];
1860
1916
  if (originalPosition === undefined) {
1861
1917
  // We never overrode this container's position; nothing to restore.
@@ -1881,10 +1937,7 @@ export class TsEmbed {
1881
1937
  if (!this.containerScrollListener) {
1882
1938
  return;
1883
1939
  }
1884
- const customContainer =
1885
- this.preRenderContainerEl && this.preRenderContainerEl !== document.body
1886
- ? this.preRenderContainerEl
1887
- : null;
1940
+ const customContainer = this.getCustomPreRenderContainer();
1888
1941
  customContainer?.removeEventListener('scroll', this.containerScrollListener);
1889
1942
  this.containerScrollListener = null;
1890
1943
  }
@@ -1978,9 +2031,15 @@ export class TsEmbed {
1978
2031
  * wrapper to overlay it.
1979
2032
  */
1980
2033
  public async showPreRender(): Promise<TsEmbed> {
2034
+ uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_SHOW_PRE_RENDER, {
2035
+ preRenderId: this.getPreRenderConfig().preRenderId,
2036
+ embedComponentType: this.viewConfig.embedComponentType,
2037
+ });
2038
+
1981
2039
  if (this.shouldWaitForRenderPromise) await this.isReadyForRenderPromise;
1982
2040
 
1983
- if (!this.viewConfig.preRenderId) {
2041
+
2042
+ if (!this.getPreRenderConfig().preRenderId) {
1984
2043
  logger.error(ERROR_MESSAGE.PRERENDER_ID_MISSING);
1985
2044
  return this;
1986
2045
  }
@@ -2016,16 +2075,13 @@ export class TsEmbed {
2016
2075
 
2017
2076
  this.syncPreRenderStyle();
2018
2077
 
2019
- const customContainer =
2020
- this.preRenderContainerEl && this.preRenderContainerEl !== document.body
2021
- ? this.preRenderContainerEl
2022
- : null;
2078
+ const customContainer = this.getCustomPreRenderContainer();
2023
2079
  if (customContainer && !this.containerScrollListener) {
2024
2080
  this.containerScrollListener = () => this.syncPreRenderStyle();
2025
2081
  customContainer.addEventListener('scroll', this.containerScrollListener);
2026
2082
  }
2027
2083
 
2028
- if (!this.viewConfig.doNotTrackPreRenderSize) {
2084
+ if (!this.getPreRenderConfig().doNotTrackPreRenderSize) {
2029
2085
  const observeTarget = (this.insertedDomEl as HTMLElement) ?? this.hostElement;
2030
2086
  this.resizeObserver = new ResizeObserver((entries) => {
2031
2087
  entries.forEach((entry) => {
@@ -2071,15 +2127,16 @@ export class TsEmbed {
2071
2127
  logger.error(ERROR_MESSAGE.SYNC_STYLE_CALLED_BEFORE_RENDER);
2072
2128
  return;
2073
2129
  }
2130
+ if (!this.getPreRenderPlaceHolderElement().isConnected) {
2131
+ logger.debug('syncPreRenderStyle skipped: placeholder is detached');
2132
+ return;
2133
+ }
2074
2134
  // Self-heal if the resolved container was remounted/detached, so we
2075
2135
  // never measure a stale node (which would collapse the wrapper).
2076
2136
  this.reconcilePreRenderContainer();
2077
2137
  const elBoundingClient = this.getPreRenderPlaceHolderElement().getBoundingClientRect();
2078
2138
 
2079
- const containerEl =
2080
- this.preRenderContainerEl && this.preRenderContainerEl !== document.body
2081
- ? this.preRenderContainerEl
2082
- : null;
2139
+ const containerEl = this.getCustomPreRenderContainer();
2083
2140
  const containerRect = containerEl?.getBoundingClientRect() ?? { x: 0, y: 0 };
2084
2141
  const scrollX = containerEl ? containerEl.scrollLeft : window.scrollX;
2085
2142
  const scrollY = containerEl ? containerEl.scrollTop : window.scrollY;
@@ -2098,16 +2155,22 @@ export class TsEmbed {
2098
2155
  * If the component is not preRendered, it issues a warning.
2099
2156
  */
2100
2157
  public hidePreRender(): void {
2158
+ uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_HIDE_PRE_RENDER, {
2159
+ preRenderId: this.getPreRenderConfig().preRenderId,
2160
+ embedComponentType: this.viewConfig.embedComponentType,
2161
+ });
2162
+
2101
2163
  logger.debug('HidePreRender Called');
2102
2164
  if (!this.isPreRenderConnected()) {
2103
2165
  // if the embed component is not preRendered , nothing to hide
2104
2166
  logger.warn('PreRender should be called before hiding it using hidePreRender.');
2105
2167
  return;
2106
2168
  }
2169
+ const { zIndex } = this.getPreRenderConfig();
2107
2170
  const preRenderHideStyles = {
2108
2171
  opacity: '0',
2109
2172
  pointerEvents: 'none',
2110
- zIndex: '-1000',
2173
+ zIndex: zIndex !== undefined ? String(zIndex) : '-1000',
2111
2174
  position: 'absolute',
2112
2175
  top: '0',
2113
2176
  left: '0',
@@ -2137,10 +2200,11 @@ export class TsEmbed {
2137
2200
  * @property {string} child - The HTML element ID for the PreRender child.
2138
2201
  */
2139
2202
  public getPreRenderIds() {
2203
+ const preRenderId = this.getPreRenderConfig().preRenderId;
2140
2204
  return {
2141
- wrapper: `${PRERENDER_WRAPPER_ID_PREFIX}${this.viewConfig.preRenderId}`,
2142
- child: `tsEmbed-pre-render-child-${this.viewConfig.preRenderId}`,
2143
- placeHolder: `tsEmbed-pre-render-placeholder-${this.viewConfig.preRenderId}`,
2205
+ wrapper: `${PRERENDER_WRAPPER_ID_PREFIX}${preRenderId}`,
2206
+ child: `tsEmbed-pre-render-child-${preRenderId}`,
2207
+ placeHolder: `tsEmbed-pre-render-placeholder-${preRenderId}`,
2144
2208
  };
2145
2209
  }
2146
2210
 
package/src/index.ts CHANGED
@@ -32,7 +32,7 @@ import { PinboardEmbed, LiveboardViewConfig, LiveboardEmbed } from './embed/live
32
32
  import { SearchEmbed, SearchViewConfig } from './embed/search';
33
33
  import { SearchBarEmbed, SearchBarViewConfig } from './embed/search-bar';
34
34
  import { SpotterAgentEmbed, SpotterAgentEmbedViewConfig, BodylessConversation, BodylessConversationViewConfig} from './embed/bodyless-conversation';
35
- import { SpotterEmbed, SpotterEmbedViewConfig, SpotterChatViewConfig, SpotterSidebarViewConfig, SpotterQueryMode, ConversationEmbed, ConversationViewConfig } from './embed/conversation';
35
+ import { SpotterEmbed, SpotterEmbedViewConfig, SpotterChatViewConfig, SpotterSidebarViewConfig, SpotterAnalystConfig, SpotterQueryMode, SpotterShareConversationConfig, StarterPromptsConfig, StarterPromptCategory, StarterPreviewDataCategory, StarterPromptQuestion, ConversationEmbed, ConversationViewConfig } from './embed/conversation';
36
36
  import { SpotterVizConfig, SpotterVizStarterPrompt, SpotterVizLoaderTip } from './embed/spotter-viz-utils';
37
37
  import {
38
38
  AuthFailureType, AuthStatus, AuthEvent, AuthEventEmitter,
@@ -88,7 +88,24 @@ import { uploadMixpanelEvent, MIXPANEL_EVENT } from './mixpanel-service';
88
88
  import { tokenizedFetch } from './tokenizedFetch';
89
89
  import { getAnswerFromQuery } from './utils/graphql/nlsService/nls-answer-service';
90
90
  import { createLiveboardWithAnswers } from './utils/liveboardService/liveboardService';
91
- import { UIPassthroughEvent } from './embed/hostEventClient/contracts';
91
+ import {
92
+ UIPassthroughEvent,
93
+ UIPassthroughContractBase,
94
+ UIPassthroughRequest,
95
+ UIPassthroughResponse,
96
+ UIPassthroughArrayResponse,
97
+ HostEventRequest,
98
+ HostEventResponse,
99
+ TriggerPayload,
100
+ TriggerResponse,
101
+ LiveboardTab,
102
+ LiveboardGroup,
103
+ ApplicabilityLevel,
104
+ Applicability,
105
+ FilterUpdate,
106
+ LiveboardFilter,
107
+ LiveboardParameter,
108
+ } from './embed/hostEventClient/contracts';
92
109
 
93
110
  export {
94
111
  init,
@@ -117,7 +134,13 @@ export {
117
134
  SpotterEmbedViewConfig,
118
135
  SpotterChatViewConfig,
119
136
  SpotterSidebarViewConfig,
137
+ SpotterAnalystConfig,
120
138
  SpotterQueryMode,
139
+ SpotterShareConversationConfig,
140
+ StarterPromptsConfig,
141
+ StarterPromptCategory,
142
+ StarterPreviewDataCategory,
143
+ StarterPromptQuestion,
121
144
  ConversationViewConfig,
122
145
  ConversationEmbed,
123
146
  AuthFailureType,
@@ -169,6 +192,25 @@ export {
169
192
  VizPoint,
170
193
  CustomActionPayload,
171
194
  UIPassthroughEvent,
195
+ // Host event payload / response contracts. These describe what to send with
196
+ // `embed.trigger(HostEvent.X, payload)` and what the returned promise
197
+ // resolves with. See `UIPassthroughContractBase` for the per-event
198
+ // request/response shapes.
199
+ UIPassthroughContractBase,
200
+ UIPassthroughRequest,
201
+ UIPassthroughResponse,
202
+ UIPassthroughArrayResponse,
203
+ HostEventRequest,
204
+ HostEventResponse,
205
+ TriggerPayload,
206
+ TriggerResponse,
207
+ LiveboardTab,
208
+ LiveboardGroup,
209
+ ApplicabilityLevel,
210
+ Applicability,
211
+ FilterUpdate,
212
+ LiveboardFilter,
213
+ LiveboardParameter,
172
214
  ListPageColumns,
173
215
  DataPanelCustomColumnGroupsAccordionState,
174
216
  CustomActionsPosition,
@@ -26,6 +26,10 @@ export const MIXPANEL_EVENT = {
26
26
  VISUAL_SDK_IFRAME_LOAD_PERFORMANCE: 'visual-sdk-iframe-load-performance',
27
27
  VISUAL_SDK_EMBED_CREATE: 'visual-sdk-embed-create',
28
28
  VERCEL_INTEGRATION_COMPLETED: 'vercel-integration-completed',
29
+ VISUAL_SDK_RENDER_CALLED: 'visual-sdk-render-called',
30
+ VISUAL_SDK_PRE_RENDER: 'visual-sdk-pre-render',
31
+ VISUAL_SDK_SHOW_PRE_RENDER: 'visual-sdk-show-pre-render',
32
+ VISUAL_SDK_HIDE_PRE_RENDER: 'visual-sdk-hide-pre-render',
29
33
  };
30
34
 
31
35
  let isMixpanelInitialized = false;
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Parity gate: every symbol exported from `src/index.ts` must also be exported
3
+ * from `src/react/all-types-export.ts`.
4
+ *
5
+ * `package.json` `exports` restricts consumers to two entry points — `.` and
6
+ * `./react` — and the React surface is a HAND-MAINTAINED duplicate export list,
7
+ * not a `export * from '../index'`. So a symbol added only to `src/index.ts` is
8
+ * invisible to every React consumer.
9
+ *
10
+ * The sibling `all-types-export.spec.ts` cannot catch this: it inspects the
11
+ * module at runtime, and type-only exports (interfaces, type aliases) are
12
+ * erased by the compiler. This spec therefore compares the two files as TEXT.
13
+ */
14
+ import * as fs from 'fs';
15
+ import * as path from 'path';
16
+
17
+ const INDEX_PATH = path.join(__dirname, '..', 'index.ts');
18
+ const REACT_EXPORT_PATH = path.join(__dirname, 'all-types-export.ts');
19
+
20
+ /**
21
+ * Symbols intentionally absent from the React surface.
22
+ * Add here only with a reason — every entry is a thing React users cannot use.
23
+ */
24
+ const REACT_EXEMPT = new Set<string>([
25
+ // React has its own component wrappers for these; the raw classes are not
26
+ // part of the /react surface.
27
+ 'SearchEmbed',
28
+ 'SearchBarEmbed',
29
+ 'LiveboardEmbed',
30
+ 'AppEmbed',
31
+ 'SpotterEmbed',
32
+ 'SpotterAgentEmbed',
33
+ 'ConversationEmbed',
34
+ 'BodylessConversation',
35
+ 'PreRenderedSearchEmbed',
36
+ 'PreRenderedSearchBarEmbed',
37
+ 'PreRenderedLiveboardEmbed',
38
+ 'PreRenderedAppEmbed',
39
+ 'PreRenderedConversationEmbed',
40
+ 'PinboardEmbed',
41
+ 'TsEmbed',
42
+ 'V1Embed',
43
+ ]);
44
+
45
+ /**
46
+ * PRE-EXISTING gaps, discovered when this spec was introduced. These are
47
+ * symbols React consumers cannot import today — most look like oversights
48
+ * rather than deliberate omissions (e.g. `ContextType`, `CustomActionPayload`,
49
+ * `VizPoint`, the Spotter view configs).
50
+ *
51
+ * This list may only ever SHRINK. Do not add to it — a new entry means a
52
+ * symbol was added to `src/index.ts` without adding it to the React surface,
53
+ * which is exactly what this spec exists to prevent. Removing entries (by
54
+ * exporting them from `all-types-export.ts`) is a welcome follow-up; it is
55
+ * deliberately out of scope for the change that introduced this gate.
56
+ */
57
+ const KNOWN_REACT_GAPS = new Set<string>([
58
+ 'AnswerService',
59
+ 'AutoMCPFrameRendererViewConfig',
60
+ 'BackgroundFormatType',
61
+ 'BodylessConversationViewConfig',
62
+ 'ConditionalFormattingComparisonType',
63
+ 'ConditionalFormattingOperator',
64
+ 'ContextMenuTriggerOptions',
65
+ 'ContextType',
66
+ 'ConversationViewConfig',
67
+ 'CustomActionPayload',
68
+ 'DataLabelFilterOperator',
69
+ 'EmbedErrorCodes',
70
+ 'EmbedErrorDetailsEvent',
71
+ 'ErrorDetailsTypes',
72
+ 'HomeLeftNavItem',
73
+ 'HomePage',
74
+ 'HomePageSearchBarMode',
75
+ 'HomepageModule',
76
+ 'LegendPosition',
77
+ 'ListPage',
78
+ 'ListPageColumns',
79
+ 'LogLevel',
80
+ 'MIXPANEL_EVENT',
81
+ 'PrimaryNavbarVersion',
82
+ 'SessionInterface',
83
+ 'SpotterAgentEmbedViewConfig',
84
+ 'SpotterChatViewConfig',
85
+ 'SpotterEmbedViewConfig',
86
+ 'SpotterQueryMode',
87
+ 'SpotterShareConversationConfig',
88
+ 'SpotterSidebarViewConfig',
89
+ 'SpotterVizConfig',
90
+ 'SpotterVizLoaderTip',
91
+ 'SpotterVizStarterPrompt',
92
+ 'TableContentDensity',
93
+ 'TableTheme',
94
+ 'UnderlyingDataPoint',
95
+ 'VisualizationOverrides',
96
+ 'VizPoint',
97
+ // Standalone helpers re-exported from src/index.ts outside the main block.
98
+ 'createLiveboardWithAnswers',
99
+ 'executeTML',
100
+ 'executeTMLInput',
101
+ 'exportTML',
102
+ 'exportTMLInput',
103
+ 'getAnswerFromQuery',
104
+ 'startAutoMCPFrameRenderer',
105
+ 'tokenizedFetch',
106
+ ]);
107
+
108
+ /**
109
+ * Extract identifiers from every `export { ... }` / `export type { ... }` block
110
+ * in a source file. Handles `a`, `a as b` (records the exported name `b`),
111
+ * comments and trailing commas.
112
+ *
113
+ * `export * from '...'` cannot be enumerated by name (the names live in another
114
+ * module), so it would silently defeat this parity gate. We refuse to run
115
+ * against it: if either file adopts a star re-export, this throws so the gate
116
+ * is extended deliberately rather than passing blind.
117
+ */
118
+ const extractExportedNames = (source: string): Set<string> => {
119
+ if (/export\s*\*/.test(source)) {
120
+ throw new Error(
121
+ 'Parity extractor found an `export *` re-export, which it cannot '
122
+ + 'enumerate by name. Extend extractExportedNames to resolve star '
123
+ + 'exports before relying on this gate.',
124
+ );
125
+ }
126
+ const names = new Set<string>();
127
+ // Matches `export { ... }` and `export type { ... }`.
128
+ const blockRe = /export\s*(?:type\s+)?\{([\s\S]*?)\}/g;
129
+ let match = blockRe.exec(source);
130
+ while (match !== null) {
131
+ match[1]
132
+ // strip line and block comments
133
+ .replace(/\/\*[\s\S]*?\*\//g, '')
134
+ .replace(/\/\/[^\n]*/g, '')
135
+ .split(',')
136
+ .map((entry) => entry.trim())
137
+ .filter(Boolean)
138
+ .forEach((entry) => {
139
+ // `foo as bar` exports the name `bar`
140
+ const parts = entry.split(/\s+as\s+/);
141
+ const exported = (parts[parts.length - 1] || '').trim();
142
+ if (/^[A-Za-z_$][\w$]*$/.test(exported)) {
143
+ names.add(exported);
144
+ }
145
+ });
146
+ match = blockRe.exec(source);
147
+ }
148
+ return names;
149
+ };
150
+
151
+ describe('react/all-types-export parity with index', () => {
152
+ it('exports every symbol that src/index.ts exports', () => {
153
+ const indexNames = extractExportedNames(fs.readFileSync(INDEX_PATH, 'utf8'));
154
+ const reactNames = extractExportedNames(fs.readFileSync(REACT_EXPORT_PATH, 'utf8'));
155
+
156
+ // Sanity: the extractor found something. Guards against a regex that
157
+ // silently matches nothing after a refactor.
158
+ expect(indexNames.size).toBeGreaterThan(50);
159
+ expect(reactNames.size).toBeGreaterThan(50);
160
+
161
+ const missing = [...indexNames]
162
+ .filter((name) => !reactNames.has(name))
163
+ .filter((name) => !REACT_EXEMPT.has(name))
164
+ .filter((name) => !KNOWN_REACT_GAPS.has(name))
165
+ .sort();
166
+
167
+ if (missing.length > 0) {
168
+ throw new Error(
169
+ 'These symbols are exported from src/index.ts but NOT from '
170
+ + 'src/react/all-types-export.ts, so React consumers cannot '
171
+ + `import them:\n ${missing.join('\n ')}\n\n`
172
+ + 'Add them to src/react/all-types-export.ts. Do NOT add them '
173
+ + 'to KNOWN_REACT_GAPS — that list is a shrinking backlog of '
174
+ + 'pre-existing gaps and must never grow.',
175
+ );
176
+ }
177
+ });
178
+
179
+ it('KNOWN_REACT_GAPS only lists symbols that are genuinely still missing', () => {
180
+ // Ratchet: once a gap is fixed, its entry must be deleted, so the list
181
+ // can only shrink.
182
+ const indexNames = extractExportedNames(fs.readFileSync(INDEX_PATH, 'utf8'));
183
+ const reactNames = extractExportedNames(fs.readFileSync(REACT_EXPORT_PATH, 'utf8'));
184
+
185
+ const stale = [...KNOWN_REACT_GAPS]
186
+ .filter((name) => reactNames.has(name) || !indexNames.has(name))
187
+ .sort();
188
+
189
+ if (stale.length > 0) {
190
+ throw new Error(
191
+ 'These entries in KNOWN_REACT_GAPS are no longer gaps (they are '
192
+ + 'now exported from the React surface, or no longer exported '
193
+ + `from src/index.ts). Delete them from the list:\n ${stale.join('\n ')}`,
194
+ );
195
+ }
196
+ });
197
+
198
+ it('exposes the host event contract types on the React surface', () => {
199
+ const reactNames = extractExportedNames(fs.readFileSync(REACT_EXPORT_PATH, 'utf8'));
200
+ [
201
+ 'UIPassthroughContractBase',
202
+ 'HostEventRequest',
203
+ 'HostEventResponse',
204
+ 'TriggerPayload',
205
+ 'TriggerResponse',
206
+ ].forEach((name) => expect(reactNames.has(name)).toBe(true));
207
+ });
208
+ });
@@ -56,8 +56,30 @@ export {
56
56
  RuntimeParameter,
57
57
  resetCachedAuthToken,
58
58
  UIPassthroughEvent,
59
+ // Host event payload / response contracts — kept in sync with src/index.ts
60
+ // (enforced by all-types-export.parity.spec.ts).
61
+ UIPassthroughContractBase,
62
+ UIPassthroughRequest,
63
+ UIPassthroughResponse,
64
+ UIPassthroughArrayResponse,
65
+ HostEventRequest,
66
+ HostEventResponse,
67
+ TriggerPayload,
68
+ TriggerResponse,
69
+ LiveboardTab,
70
+ LiveboardGroup,
71
+ ApplicabilityLevel,
72
+ Applicability,
73
+ FilterUpdate,
74
+ LiveboardFilter,
75
+ LiveboardParameter,
59
76
  DataPanelCustomColumnGroupsAccordionState,
60
77
  InterceptedApiType,
61
78
  CustomActionsPosition,
62
79
  CustomActionTarget,
80
+ SpotterAnalystConfig,
81
+ StarterPromptsConfig,
82
+ StarterPromptCategory,
83
+ StarterPreviewDataCategory,
84
+ StarterPromptQuestion,
63
85
  } from '../index';