@thoughtspot/visual-embed-sdk 1.49.1 → 1.49.3
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.
- package/cjs/package.json +4 -10
- package/cjs/src/css-variables.d.ts +17 -0
- package/cjs/src/css-variables.d.ts.map +1 -1
- package/cjs/src/embed/app.d.ts +7 -1
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +4 -1
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +97 -0
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +8 -0
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js +2 -1
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +12 -0
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/events.spec.js +5 -0
- package/cjs/src/embed/events.spec.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +6 -0
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +4 -1
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +11 -0
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.d.ts +29 -0
- package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts +38 -0
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +166 -9
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +237 -0
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/index.d.ts +2 -2
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/types.d.ts +87 -4
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +47 -3
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.spec.js +15 -0
- package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
- package/cjs/src/utils/processTrigger.d.ts.map +1 -1
- package/cjs/src/utils/processTrigger.js +6 -5
- package/cjs/src/utils/processTrigger.js.map +1 -1
- package/cjs/src/utils/processTrigger.spec.js +13 -0
- package/cjs/src/utils/processTrigger.spec.js.map +1 -1
- package/cjs/src/utils.d.ts +10 -0
- package/cjs/src/utils.d.ts.map +1 -1
- package/cjs/src/utils.js +25 -4
- package/cjs/src/utils.js.map +1 -1
- package/cjs/src/utils.spec.js +48 -0
- package/cjs/src/utils.spec.js.map +1 -1
- package/dist/{index-B6Rn561t.js → index-DsSQndIB.js} +303 -187
- package/dist/src/css-variables.d.ts +17 -0
- package/dist/src/css-variables.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +7 -1
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +8 -0
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +6 -0
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/spotter-viz-utils.d.ts +29 -0
- package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +38 -0
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +87 -4
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/processTrigger.d.ts.map +1 -1
- package/dist/src/utils.d.ts +10 -0
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +282 -35
- package/dist/tsembed-react.js +583 -220
- package/dist/tsembed.es.js +282 -35
- package/dist/tsembed.js +583 -220
- package/dist/visual-embed-sdk-react-full.d.ts +190 -4
- package/dist/visual-embed-sdk-react.d.ts +190 -4
- package/dist/visual-embed-sdk.d.ts +190 -4
- package/lib/package.json +4 -10
- package/lib/src/css-variables.d.ts +17 -0
- package/lib/src/css-variables.d.ts.map +1 -1
- package/lib/src/embed/app.d.ts +7 -1
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +4 -1
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +97 -0
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +8 -0
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js +2 -1
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +12 -0
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/events.spec.js +5 -0
- package/lib/src/embed/events.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +6 -0
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +4 -1
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +11 -0
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/spotter-viz-utils.d.ts +29 -0
- package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -1
- package/lib/src/embed/spotter-viz-utils.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +38 -0
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +167 -10
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +237 -0
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/index.d.ts +2 -2
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js.map +1 -1
- package/lib/src/types.d.ts +87 -4
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +47 -3
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.spec.js +15 -0
- package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
- package/lib/src/utils/processTrigger.d.ts.map +1 -1
- package/lib/src/utils/processTrigger.js +6 -5
- package/lib/src/utils/processTrigger.js.map +1 -1
- package/lib/src/utils/processTrigger.spec.js +13 -0
- package/lib/src/utils/processTrigger.spec.js.map +1 -1
- package/lib/src/utils.d.ts +10 -0
- package/lib/src/utils.d.ts.map +1 -1
- package/lib/src/utils.js +22 -1
- package/lib/src/utils.js.map +1 -1
- package/lib/src/utils.spec.js +49 -1
- package/lib/src/utils.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +190 -4
- package/package.json +4 -10
- package/src/css-variables.ts +20 -0
- package/src/embed/app.spec.ts +109 -0
- package/src/embed/app.ts +11 -1
- package/src/embed/conversation.spec.ts +17 -0
- package/src/embed/conversation.ts +10 -0
- package/src/embed/events.spec.ts +7 -0
- package/src/embed/liveboard.spec.ts +15 -0
- package/src/embed/liveboard.ts +10 -0
- package/src/embed/spotter-viz-utils.ts +30 -0
- package/src/embed/ts-embed.spec.ts +294 -0
- package/src/embed/ts-embed.ts +180 -9
- package/src/index.ts +2 -1
- package/src/types.ts +86 -3
- package/src/utils/graphql/answerService/answerService.spec.ts +18 -0
- package/src/utils/processTrigger.spec.ts +23 -0
- package/src/utils/processTrigger.ts +8 -6
- package/src/utils.spec.ts +63 -0
- package/src/utils.ts +25 -1
package/src/types.ts
CHANGED
|
@@ -1108,6 +1108,45 @@ export interface BaseViewConfig extends ApiInterceptFlags {
|
|
|
1108
1108
|
* ```
|
|
1109
1109
|
*/
|
|
1110
1110
|
doNotTrackPreRenderSize?: boolean;
|
|
1111
|
+
/**
|
|
1112
|
+
* The DOM element or CSS selector string specifying the container into which
|
|
1113
|
+
* the pre-rendered wrapper is inserted. Defaults to `document.body` when not
|
|
1114
|
+
* specified.
|
|
1115
|
+
*
|
|
1116
|
+
* **When to use a target container:** set this when the pre-render should
|
|
1117
|
+
* live somewhere other than `document.body` — for example when `<body>` has
|
|
1118
|
+
* `overflow: hidden` and scrolling is handled by an inner element, or when
|
|
1119
|
+
* you need the wrapper to sit inside a specific stacking/positioning context.
|
|
1120
|
+
* The wrapper is positioned to track the embedding element within this
|
|
1121
|
+
* container, so choose the scrollable/positioned ancestor you want it
|
|
1122
|
+
* aligned to.
|
|
1123
|
+
*
|
|
1124
|
+
* **Pass a stable container:** the wrapper is mounted into the resolved
|
|
1125
|
+
* container once, during `preRender()`. The container must stay mounted for
|
|
1126
|
+
* the lifetime of the pre-render — if the host app unmounts and remounts it
|
|
1127
|
+
* (for example React replacing the node), the wrapper is orphaned on the
|
|
1128
|
+
* detached node. Mount the container above the part of the tree that
|
|
1129
|
+
* re-renders so its identity is stable. Prefer a CSS selector string over a
|
|
1130
|
+
* raw element: a selector can be re-resolved to the fresh node on the next
|
|
1131
|
+
* reposition, whereas an element reference cannot be recovered once detached.
|
|
1132
|
+
*
|
|
1133
|
+
* When the embed host lives inside a Shadow DOM, a selector string is
|
|
1134
|
+
* resolved against that shadow root as well (since `document.querySelector`
|
|
1135
|
+
* cannot pierce shadow boundaries); pass the element directly if the
|
|
1136
|
+
* container lives in a different root.
|
|
1137
|
+
*
|
|
1138
|
+
* @type {string | HTMLElement}
|
|
1139
|
+
* @version SDK: 1.49.2 | ThoughtSpot: *
|
|
1140
|
+
* @example
|
|
1141
|
+
* ```js
|
|
1142
|
+
* const embed = new LiveboardEmbed('#tsEmbed', {
|
|
1143
|
+
* preRenderId: 'my-liveboard',
|
|
1144
|
+
* // Prefer a selector for a stable, scrollable container.
|
|
1145
|
+
* preRenderContainer: '#my-scroll-container',
|
|
1146
|
+
* });
|
|
1147
|
+
* ```
|
|
1148
|
+
*/
|
|
1149
|
+
preRenderContainer?: string | HTMLElement;
|
|
1111
1150
|
/**
|
|
1112
1151
|
* Enable the V2 shell. This can provide performance benefits
|
|
1113
1152
|
* due to a lighter-weight shell.
|
|
@@ -4150,11 +4189,30 @@ export enum HostEvent {
|
|
|
4150
4189
|
/**
|
|
4151
4190
|
* Navigate to a specific page in the embedded ThoughtSpot application.
|
|
4152
4191
|
* This is the same as calling `appEmbed.navigateToPage(path, true)`.
|
|
4153
|
-
*
|
|
4154
|
-
*
|
|
4192
|
+
*
|
|
4193
|
+
* Accepts either a plain value or an object with `path`
|
|
4194
|
+
* and an optional `replace` flag.
|
|
4195
|
+
*
|
|
4196
|
+
* @param data - A string path, a numeric history delta, or an object
|
|
4197
|
+
* `{ path: string | number, replace?: boolean }`.
|
|
4198
|
+
* - `path` — the route to navigate to, or a history delta such as `1`
|
|
4199
|
+
* or `-1` (calls `window.history.go()`).
|
|
4200
|
+
* - `replace` — when `true`, replaces the current history entry instead
|
|
4201
|
+
* of pushing a new one (uses `window.location.replace`).
|
|
4202
|
+
*
|
|
4155
4203
|
* @example
|
|
4156
4204
|
* ```js
|
|
4157
|
-
*
|
|
4205
|
+
* // Preferred: use navigateToPage directly
|
|
4206
|
+
* appEmbed.navigateToPage(-1);
|
|
4207
|
+
*
|
|
4208
|
+
* // Numeric delta — go back one step
|
|
4209
|
+
* appEmbed.trigger(HostEvent.Navigate, -1);
|
|
4210
|
+
*
|
|
4211
|
+
* // String path — push a new history entry
|
|
4212
|
+
* appEmbed.trigger(HostEvent.Navigate, 'home');
|
|
4213
|
+
*
|
|
4214
|
+
* // Object format — replace current history entry
|
|
4215
|
+
* appEmbed.trigger(HostEvent.Navigate, { path: 'home', replace: true }); // SDK: 1.51.0 | ThoughtSpot Cloud: 26.8.0.cl
|
|
4158
4216
|
* ```
|
|
4159
4217
|
* @version SDK: 1.12.0 | ThoughtSpot: 8.4.0.cl, 8.4.1.sw
|
|
4160
4218
|
*/
|
|
@@ -6149,6 +6207,7 @@ export enum Param {
|
|
|
6149
6207
|
EnableLiveboardDataCache = 'enableLiveboardDataCache',
|
|
6150
6208
|
SpotterFileUploadEnabled = 'spotterFileUploadEnabled',
|
|
6151
6209
|
SpotterFileUploadFileTypes = 'spotterFileUploadFileTypes',
|
|
6210
|
+
IsStarterPromptsEnabled = 'enableStarterPrompts',
|
|
6152
6211
|
}
|
|
6153
6212
|
|
|
6154
6213
|
/**
|
|
@@ -6801,6 +6860,16 @@ export enum Action {
|
|
|
6801
6860
|
* @version SDK: 1.9.0 | ThoughtSpot: 8.1.0.cl, 8.4.1.sw
|
|
6802
6861
|
*/
|
|
6803
6862
|
AddToFavorites = 'addToFavorites',
|
|
6863
|
+
/**
|
|
6864
|
+
* Remove from Favorites option in home page v3 sidebar.
|
|
6865
|
+
* Allows removing an object from the user's favorites list from home-page v3 sidebar.
|
|
6866
|
+
* @version SDK: 1.51.0 | ThoughtSpot Cloud: 26.8.0.cl
|
|
6867
|
+
* @example
|
|
6868
|
+
* ```js
|
|
6869
|
+
* disabledActions: [Action.RemoveFromFavorites]
|
|
6870
|
+
* ```
|
|
6871
|
+
*/
|
|
6872
|
+
RemoveFromFavorites = 'removeFromFavorites',
|
|
6804
6873
|
/**
|
|
6805
6874
|
* The edit icon on Liveboards (Classic experience).
|
|
6806
6875
|
* @example
|
|
@@ -7879,6 +7948,20 @@ export enum Action {
|
|
|
7879
7948
|
* ```
|
|
7880
7949
|
*/
|
|
7881
7950
|
SpotterViz = 'spotterViz',
|
|
7951
|
+
/**
|
|
7952
|
+
* The reference-mode toggle button inside the SpotterViz chat input.
|
|
7953
|
+
* When users enable reference mode, clicking tiles, filters, or
|
|
7954
|
+
* parameters adds them as chat context. Hide this action to remove
|
|
7955
|
+
* the reference-mode capability entirely.
|
|
7956
|
+
* Visible by default.
|
|
7957
|
+
* @version SDK: 1.51.0 | ThoughtSpot Cloud: 26.8.0.cl
|
|
7958
|
+
* @example
|
|
7959
|
+
* ```js
|
|
7960
|
+
* hiddenActions: [Action.SpotterVizReferenceMode]
|
|
7961
|
+
* disabledActions: [Action.SpotterVizReferenceMode]
|
|
7962
|
+
* ```
|
|
7963
|
+
*/
|
|
7964
|
+
SpotterVizReferenceMode = 'spotterVizReferenceMode',
|
|
7882
7965
|
/**
|
|
7883
7966
|
* Clears browser cache and fetches new data for liveboard ChartViz Containers.
|
|
7884
7967
|
* Requires `enableLiveboardDataCache` to be enabled.
|
|
@@ -707,4 +707,22 @@ describe('Answer service tests', () => {
|
|
|
707
707
|
expect(answer.name).toBe('name');
|
|
708
708
|
expect(answer.id).toBe('bar');
|
|
709
709
|
});
|
|
710
|
+
|
|
711
|
+
test('getTML parses nested objects and arrays from the YAML edoc', async () => {
|
|
712
|
+
const edoc = [
|
|
713
|
+
'answer:',
|
|
714
|
+
' name: Revenue answer',
|
|
715
|
+
' visualizations:',
|
|
716
|
+
' - id: viz-1',
|
|
717
|
+
' type: TABLE',
|
|
718
|
+
].join('\n');
|
|
719
|
+
fetchMock.mockResponseOnce(JSON.stringify({
|
|
720
|
+
data: { UnsavedAnswer_getTML: { object: [{ edoc }] } },
|
|
721
|
+
}));
|
|
722
|
+
|
|
723
|
+
const { answer } = await createAnswerService().getTML();
|
|
724
|
+
|
|
725
|
+
expect(answer.name).toBe('Revenue answer');
|
|
726
|
+
expect(answer.visualizations).toEqual([{ id: 'viz-1', type: 'TABLE' }]);
|
|
727
|
+
});
|
|
710
728
|
});
|
|
@@ -94,6 +94,29 @@ describe('Unit test for processTrigger', () => {
|
|
|
94
94
|
await expect(triggerPromise).resolves.toEqual(null);
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
test('should clear the timeout when response arrives before TRIGGER_TIMEOUT', async () => {
|
|
98
|
+
const messageType = HostEvent.Search;
|
|
99
|
+
const thoughtSpotHost = 'http://localhost:3000';
|
|
100
|
+
const data = {};
|
|
101
|
+
mockMessageChannel();
|
|
102
|
+
const clearTimeoutSpy = jest.spyOn(global, 'clearTimeout');
|
|
103
|
+
|
|
104
|
+
const triggerPromise = _processTriggerInstance.processTrigger(
|
|
105
|
+
iFrame,
|
|
106
|
+
messageType,
|
|
107
|
+
thoughtSpotHost,
|
|
108
|
+
data,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const res = { data: { test: '123' } };
|
|
112
|
+
messageChannelMock.port1.onmessage(res);
|
|
113
|
+
|
|
114
|
+
expect(clearTimeoutSpy).toHaveBeenCalled();
|
|
115
|
+
await expect(triggerPromise).resolves.toEqual(res.data);
|
|
116
|
+
|
|
117
|
+
clearTimeoutSpy.mockRestore();
|
|
118
|
+
});
|
|
119
|
+
|
|
97
120
|
test('should close channel.port1 when timeout exceeds TRIGGER_TIMEOUT', async () => {
|
|
98
121
|
const messageType = HostEvent.Search;
|
|
99
122
|
const thoughtSpotHost = 'http://localhost:3000';
|
|
@@ -70,7 +70,15 @@ export function processTrigger(
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const channel = new MessageChannel();
|
|
73
|
+
|
|
74
|
+
// Close the messageChannel and resolve the promise if timeout.
|
|
75
|
+
const timeoutId = setTimeout(() => {
|
|
76
|
+
channel.port1.close();
|
|
77
|
+
res(new Error(ERROR_MESSAGE.TRIGGER_TIMED_OUT));
|
|
78
|
+
}, TRIGGER_TIMEOUT);
|
|
79
|
+
|
|
73
80
|
channel.port1.onmessage = ({ data: responseData }) => {
|
|
81
|
+
clearTimeout(timeoutId);
|
|
74
82
|
channel.port1.close();
|
|
75
83
|
const error = responseData?.error || responseData?.data?.error;
|
|
76
84
|
if (error) {
|
|
@@ -80,12 +88,6 @@ export function processTrigger(
|
|
|
80
88
|
}
|
|
81
89
|
};
|
|
82
90
|
|
|
83
|
-
// Close the messageChannel and resolve the promise if timeout.
|
|
84
|
-
setTimeout(() => {
|
|
85
|
-
channel.port1.close();
|
|
86
|
-
res(new Error(ERROR_MESSAGE.TRIGGER_TIMED_OUT));
|
|
87
|
-
}, TRIGGER_TIMEOUT);
|
|
88
|
-
|
|
89
91
|
return postIframeMessage(iFrame, { type: messageType, data, context }, thoughtSpotHost, channel);
|
|
90
92
|
});
|
|
91
93
|
}
|
package/src/utils.spec.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
resetValueFromWindow,
|
|
27
27
|
validateHttpUrl,
|
|
28
28
|
setParamIfDefined,
|
|
29
|
+
querySelectorAcrossShadowRoot,
|
|
29
30
|
} from './utils';
|
|
30
31
|
import { RuntimeFilterOp } from './types';
|
|
31
32
|
import { logger } from './utils/logger';
|
|
@@ -855,6 +856,68 @@ describe('getClippingAncestors', () => {
|
|
|
855
856
|
});
|
|
856
857
|
});
|
|
857
858
|
|
|
859
|
+
describe('querySelectorAcrossShadowRoot', () => {
|
|
860
|
+
it('should resolve a selector from the light DOM document', () => {
|
|
861
|
+
const el = document.createElement('div');
|
|
862
|
+
el.id = 'light-dom-target';
|
|
863
|
+
document.body.appendChild(el);
|
|
864
|
+
|
|
865
|
+
expect(querySelectorAcrossShadowRoot('#light-dom-target')).toBe(el);
|
|
866
|
+
|
|
867
|
+
el.remove();
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
it('should resolve a selector inside the reference node shadow root when the document misses', () => {
|
|
871
|
+
const host = document.createElement('div');
|
|
872
|
+
document.body.appendChild(host);
|
|
873
|
+
const shadow = host.attachShadow({ mode: 'open' });
|
|
874
|
+
const container = document.createElement('div');
|
|
875
|
+
container.id = 'shadow-target';
|
|
876
|
+
const reference = document.createElement('div');
|
|
877
|
+
shadow.appendChild(container);
|
|
878
|
+
shadow.appendChild(reference);
|
|
879
|
+
|
|
880
|
+
// document.querySelector cannot see into the shadow root.
|
|
881
|
+
expect(document.querySelector('#shadow-target')).toBeNull();
|
|
882
|
+
expect(querySelectorAcrossShadowRoot('#shadow-target', reference)).toBe(container);
|
|
883
|
+
|
|
884
|
+
host.remove();
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
it('should prefer the document match over the shadow root', () => {
|
|
888
|
+
const lightEl = document.createElement('div');
|
|
889
|
+
lightEl.id = 'shared-id';
|
|
890
|
+
document.body.appendChild(lightEl);
|
|
891
|
+
|
|
892
|
+
const host = document.createElement('div');
|
|
893
|
+
document.body.appendChild(host);
|
|
894
|
+
const shadow = host.attachShadow({ mode: 'open' });
|
|
895
|
+
const shadowEl = document.createElement('div');
|
|
896
|
+
shadowEl.id = 'shared-id';
|
|
897
|
+
const reference = document.createElement('div');
|
|
898
|
+
shadow.appendChild(shadowEl);
|
|
899
|
+
shadow.appendChild(reference);
|
|
900
|
+
|
|
901
|
+
expect(querySelectorAcrossShadowRoot('#shared-id', reference)).toBe(lightEl);
|
|
902
|
+
|
|
903
|
+
lightEl.remove();
|
|
904
|
+
host.remove();
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
it('should return null when nothing matches and the reference node is in the light DOM', () => {
|
|
908
|
+
const reference = document.createElement('div');
|
|
909
|
+
document.body.appendChild(reference);
|
|
910
|
+
|
|
911
|
+
expect(querySelectorAcrossShadowRoot('#does-not-exist', reference)).toBeNull();
|
|
912
|
+
|
|
913
|
+
reference.remove();
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
it('should return null when no reference node is provided and the document misses', () => {
|
|
917
|
+
expect(querySelectorAcrossShadowRoot('#does-not-exist')).toBeNull();
|
|
918
|
+
});
|
|
919
|
+
});
|
|
920
|
+
|
|
858
921
|
describe('getEffectiveClippingAncestors', () => {
|
|
859
922
|
it('should return an empty list when element is missing', () => {
|
|
860
923
|
expect(getEffectiveClippingAncestors(null as unknown as HTMLElement)).toEqual([]);
|
package/src/utils.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @author Ayon Ghosh <ayon.ghosh@thoughtspot.com>
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import merge from 'ts-deepmerge';
|
|
9
|
+
import { merge } from 'ts-deepmerge';
|
|
10
10
|
import {
|
|
11
11
|
EmbedConfig,
|
|
12
12
|
QueryParams,
|
|
@@ -291,6 +291,30 @@ export function getDOMNode(domSelector: DOMSelector): HTMLElement {
|
|
|
291
291
|
return typeof domSelector === 'string' ? document.querySelector(domSelector) : domSelector;
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Resolves a CSS selector to an element. `document.querySelector` cannot pierce
|
|
296
|
+
* shadow boundaries, so when the document lookup misses and a reference node is
|
|
297
|
+
* provided, this also searches the shadow root the reference node lives in —
|
|
298
|
+
* letting a selector target an element inside the same shadow root as the embed
|
|
299
|
+
* instead of silently falling back to the light DOM.
|
|
300
|
+
* @param selector CSS selector string.
|
|
301
|
+
* @param referenceNode Node whose shadow root is searched when the document lookup misses.
|
|
302
|
+
*/
|
|
303
|
+
export function querySelectorAcrossShadowRoot(
|
|
304
|
+
selector: string,
|
|
305
|
+
referenceNode?: Node | null,
|
|
306
|
+
): Element | null {
|
|
307
|
+
const fromDocument = document.querySelector(selector);
|
|
308
|
+
if (fromDocument) {
|
|
309
|
+
return fromDocument;
|
|
310
|
+
}
|
|
311
|
+
const rootNode = referenceNode?.getRootNode?.();
|
|
312
|
+
if (typeof ShadowRoot !== 'undefined' && rootNode instanceof ShadowRoot) {
|
|
313
|
+
return rootNode.querySelector(selector);
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
|
|
294
318
|
export const deepMerge = (target: any, source: any) => merge(target, source);
|
|
295
319
|
|
|
296
320
|
export const getOperationNameFromQuery = (query: string) => {
|