@thoughtspot/visual-embed-sdk 1.48.0 → 1.49.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.
- package/cjs/package.json +1 -1
- package/cjs/src/css-variables.d.ts +140 -0
- package/cjs/src/css-variables.d.ts.map +1 -1
- package/cjs/src/embed/app.d.ts +62 -1
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +57 -6
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +191 -1
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.js +7 -2
- package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.spec.js +385 -6
- package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/cjs/src/embed/base.d.ts +1 -0
- package/cjs/src/embed/base.d.ts.map +1 -1
- package/cjs/src/embed/base.js +13 -1
- package/cjs/src/embed/base.js.map +1 -1
- package/cjs/src/embed/base.spec.js +21 -0
- package/cjs/src/embed/base.spec.js.map +1 -1
- package/cjs/src/embed/bodyless-conversation.spec.js +86 -0
- package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +16 -1
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js +5 -1
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +26 -0
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +47 -1
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +47 -6
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +129 -1
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.d.ts +85 -0
- package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -0
- package/cjs/src/embed/spotter-viz-utils.js +17 -0
- package/cjs/src/embed/spotter-viz-utils.js.map +1 -0
- package/cjs/src/embed/spotter-viz-utils.spec.d.ts +2 -0
- package/cjs/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
- package/cjs/src/embed/spotter-viz-utils.spec.js +31 -0
- package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -0
- package/cjs/src/embed/ts-embed.d.ts +58 -38
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +247 -151
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +369 -123
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/index.d.ts +2 -1
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/mixpanel-service.js +2 -2
- package/cjs/src/mixpanel-service.js.map +1 -1
- package/cjs/src/react/index.d.ts.map +1 -1
- package/cjs/src/react/index.js +3 -0
- package/cjs/src/react/index.js.map +1 -1
- package/cjs/src/types.d.ts +267 -27
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +223 -19
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/authService/tokenizedAuthService.spec.js +6 -7
- package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
- package/cjs/src/utils/logger.js +2 -1
- package/cjs/src/utils/logger.js.map +1 -1
- package/cjs/src/utils/logger.spec.d.ts +1 -0
- package/cjs/src/utils/logger.spec.d.ts.map +1 -1
- package/cjs/src/utils/logger.spec.js +10 -9
- package/cjs/src/utils/logger.spec.js.map +1 -1
- package/cjs/src/utils/sdk-version.d.ts +2 -0
- package/cjs/src/utils/sdk-version.d.ts.map +1 -0
- package/cjs/src/utils/sdk-version.js +7 -0
- package/cjs/src/utils/sdk-version.js.map +1 -0
- package/cjs/src/utils.d.ts +4 -1
- package/cjs/src/utils.d.ts.map +1 -1
- package/cjs/src/utils.js +107 -10
- package/cjs/src/utils.js.map +1 -1
- package/cjs/src/utils.spec.js +163 -4
- package/cjs/src/utils.spec.js.map +1 -1
- package/dist/{index-Ck-r09gt.js → index-B6Rn561t.js} +1 -1
- package/dist/src/css-variables.d.ts +140 -0
- package/dist/src/css-variables.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +62 -1
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/base.d.ts +1 -0
- package/dist/src/embed/base.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +16 -1
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +47 -1
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/spotter-viz-utils.d.ts +85 -0
- package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -0
- package/dist/src/embed/spotter-viz-utils.spec.d.ts +2 -0
- package/dist/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
- package/dist/src/embed/ts-embed.d.ts +58 -38
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/react/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +267 -27
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/logger.spec.d.ts +1 -0
- package/dist/src/utils/logger.spec.d.ts.map +1 -1
- package/dist/src/utils/sdk-version.d.ts +2 -0
- package/dist/src/utils/sdk-version.d.ts.map +1 -0
- package/dist/src/utils.d.ts +4 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +3710 -3226
- package/dist/tsembed-react.js +3360 -2876
- package/dist/tsembed.es.js +3715 -3229
- package/dist/tsembed.js +3710 -3224
- package/dist/visual-embed-sdk-react-full.d.ts +643 -63
- package/dist/visual-embed-sdk-react.d.ts +643 -63
- package/dist/visual-embed-sdk.d.ts +658 -65
- package/lib/package.json +1 -1
- package/lib/src/css-variables.d.ts +140 -0
- package/lib/src/css-variables.d.ts.map +1 -1
- package/lib/src/embed/app.d.ts +62 -1
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +58 -7
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +192 -2
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.js +7 -2
- package/lib/src/embed/auto-frame-renderer.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.spec.js +387 -8
- package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/lib/src/embed/base.d.ts +1 -0
- package/lib/src/embed/base.d.ts.map +1 -1
- package/lib/src/embed/base.js +11 -0
- package/lib/src/embed/base.js.map +1 -1
- package/lib/src/embed/base.spec.js +22 -1
- package/lib/src/embed/base.spec.js.map +1 -1
- package/lib/src/embed/bodyless-conversation.spec.js +86 -0
- package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +16 -1
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js +5 -1
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +27 -1
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +47 -1
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +48 -7
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +129 -1
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/spotter-viz-utils.d.ts +85 -0
- package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -0
- package/lib/src/embed/spotter-viz-utils.js +13 -0
- package/lib/src/embed/spotter-viz-utils.js.map +1 -0
- package/lib/src/embed/spotter-viz-utils.spec.d.ts +2 -0
- package/lib/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
- package/lib/src/embed/spotter-viz-utils.spec.js +29 -0
- package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -0
- package/lib/src/embed/ts-embed.d.ts +58 -38
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +249 -153
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +369 -123
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/index.d.ts +2 -1
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js.map +1 -1
- package/lib/src/mixpanel-service.js +1 -1
- package/lib/src/mixpanel-service.js.map +1 -1
- package/lib/src/react/index.d.ts.map +1 -1
- package/lib/src/react/index.js +3 -0
- package/lib/src/react/index.js.map +1 -1
- package/lib/src/types.d.ts +267 -27
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +223 -19
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/authService/tokenizedAuthService.spec.js +6 -7
- package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
- package/lib/src/utils/logger.js +2 -1
- package/lib/src/utils/logger.js.map +1 -1
- package/lib/src/utils/logger.spec.d.ts +1 -0
- package/lib/src/utils/logger.spec.d.ts.map +1 -1
- package/lib/src/utils/logger.spec.js +10 -9
- package/lib/src/utils/logger.spec.js.map +1 -1
- package/lib/src/utils/sdk-version.d.ts +2 -0
- package/lib/src/utils/sdk-version.d.ts.map +1 -0
- package/lib/src/utils/sdk-version.js +3 -0
- package/lib/src/utils/sdk-version.js.map +1 -0
- package/lib/src/utils.d.ts +4 -1
- package/lib/src/utils.d.ts.map +1 -1
- package/lib/src/utils.js +103 -9
- package/lib/src/utils.js.map +1 -1
- package/lib/src/utils.spec.js +164 -5
- package/lib/src/utils.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +658 -65
- package/package.json +1 -1
- package/src/css-variables.ts +175 -1
- package/src/embed/app.spec.ts +247 -3
- package/src/embed/app.ts +125 -5
- package/src/embed/auto-frame-renderer.spec.ts +457 -58
- package/src/embed/auto-frame-renderer.ts +7 -2
- package/src/embed/base.spec.ts +25 -1
- package/src/embed/base.ts +19 -5
- package/src/embed/bodyless-conversation.spec.ts +93 -0
- package/src/embed/conversation.spec.ts +34 -0
- package/src/embed/conversation.ts +22 -1
- package/src/embed/liveboard.spec.ts +149 -1
- package/src/embed/liveboard.ts +102 -6
- package/src/embed/spotter-viz-utils.spec.ts +30 -0
- package/src/embed/spotter-viz-utils.ts +94 -0
- package/src/embed/ts-embed.spec.ts +532 -234
- package/src/embed/ts-embed.ts +384 -258
- package/src/index.ts +3 -0
- package/src/mixpanel-service.ts +1 -1
- package/src/react/index.tsx +3 -0
- package/src/types.ts +284 -23
- package/src/utils/authService/tokenizedAuthService.spec.ts +6 -6
- package/src/utils/logger.spec.ts +11 -9
- package/src/utils/logger.ts +2 -2
- package/src/utils/sdk-version.ts +3 -0
- package/src/utils.spec.ts +200 -4
- package/src/utils.ts +128 -9
package/src/utils.spec.ts
CHANGED
|
@@ -18,6 +18,9 @@ import {
|
|
|
18
18
|
getTypeFromValue,
|
|
19
19
|
arrayIncludesString,
|
|
20
20
|
calculateVisibleElementData,
|
|
21
|
+
getClippingAncestors,
|
|
22
|
+
getEffectiveClippingAncestors,
|
|
23
|
+
getScrollableAncestors,
|
|
21
24
|
formatTemplate,
|
|
22
25
|
isValidCssMargin,
|
|
23
26
|
resetValueFromWindow,
|
|
@@ -519,7 +522,7 @@ describe('calculateVisibleElementData', () => {
|
|
|
519
522
|
height: 200,
|
|
520
523
|
} as DOMRect);
|
|
521
524
|
|
|
522
|
-
const result = calculateVisibleElementData(mockElement);
|
|
525
|
+
const result = calculateVisibleElementData(mockElement, true);
|
|
523
526
|
|
|
524
527
|
expect(result).toEqual({
|
|
525
528
|
top: 0, // Not clipped from top
|
|
@@ -529,6 +532,15 @@ describe('calculateVisibleElementData', () => {
|
|
|
529
532
|
});
|
|
530
533
|
});
|
|
531
534
|
|
|
535
|
+
it('should return zero dimensions when element is missing', () => {
|
|
536
|
+
expect(calculateVisibleElementData(null as unknown as HTMLElement)).toEqual({
|
|
537
|
+
top: 0,
|
|
538
|
+
height: 0,
|
|
539
|
+
left: 0,
|
|
540
|
+
width: 0,
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
|
|
532
544
|
it('should calculate data for element clipped from top', () => {
|
|
533
545
|
// Mock getBoundingClientRect for element partially above viewport
|
|
534
546
|
jest.spyOn(mockElement, 'getBoundingClientRect').mockReturnValue({
|
|
@@ -540,7 +552,7 @@ describe('calculateVisibleElementData', () => {
|
|
|
540
552
|
height: 200,
|
|
541
553
|
} as DOMRect);
|
|
542
554
|
|
|
543
|
-
const result = calculateVisibleElementData(mockElement);
|
|
555
|
+
const result = calculateVisibleElementData(mockElement, true);
|
|
544
556
|
|
|
545
557
|
expect(result).toEqual({
|
|
546
558
|
top: 50, // Clipped 50px from top
|
|
@@ -561,7 +573,7 @@ describe('calculateVisibleElementData', () => {
|
|
|
561
573
|
height: 200,
|
|
562
574
|
} as DOMRect);
|
|
563
575
|
|
|
564
|
-
const result = calculateVisibleElementData(mockElement);
|
|
576
|
+
const result = calculateVisibleElementData(mockElement, true);
|
|
565
577
|
|
|
566
578
|
expect(result).toEqual({
|
|
567
579
|
top: 0, // Not clipped from top
|
|
@@ -582,7 +594,7 @@ describe('calculateVisibleElementData', () => {
|
|
|
582
594
|
height: 350,
|
|
583
595
|
} as DOMRect);
|
|
584
596
|
|
|
585
|
-
const result = calculateVisibleElementData(mockElement);
|
|
597
|
+
const result = calculateVisibleElementData(mockElement, true);
|
|
586
598
|
|
|
587
599
|
expect(result).toEqual({
|
|
588
600
|
top: 0, // Not clipped from top
|
|
@@ -717,6 +729,190 @@ describe('calculateVisibleElementData', () => {
|
|
|
717
729
|
width: 1200, // Full viewport width
|
|
718
730
|
});
|
|
719
731
|
});
|
|
732
|
+
|
|
733
|
+
it('should calculate data clipped by a scrollable parent', () => {
|
|
734
|
+
const scrollContainer = document.createElement('div');
|
|
735
|
+
scrollContainer.style.overflow = 'auto';
|
|
736
|
+
scrollContainer.appendChild(mockElement);
|
|
737
|
+
|
|
738
|
+
jest.spyOn(scrollContainer, 'getBoundingClientRect').mockReturnValue({
|
|
739
|
+
top: 100,
|
|
740
|
+
left: 50,
|
|
741
|
+
bottom: 600,
|
|
742
|
+
right: 650,
|
|
743
|
+
width: 600,
|
|
744
|
+
height: 500,
|
|
745
|
+
} as DOMRect);
|
|
746
|
+
|
|
747
|
+
jest.spyOn(mockElement, 'getBoundingClientRect').mockReturnValue({
|
|
748
|
+
top: -100,
|
|
749
|
+
left: 50,
|
|
750
|
+
bottom: 900,
|
|
751
|
+
right: 650,
|
|
752
|
+
width: 600,
|
|
753
|
+
height: 1000,
|
|
754
|
+
} as DOMRect);
|
|
755
|
+
|
|
756
|
+
const result = calculateVisibleElementData(mockElement, true);
|
|
757
|
+
|
|
758
|
+
expect(result).toEqual({
|
|
759
|
+
top: 200,
|
|
760
|
+
height: 500,
|
|
761
|
+
left: 0,
|
|
762
|
+
width: 600,
|
|
763
|
+
});
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
it('should calculate data clipped by a non-scroll clipping parent', () => {
|
|
767
|
+
const clippingContainer = document.createElement('div');
|
|
768
|
+
clippingContainer.style.overflow = 'hidden';
|
|
769
|
+
clippingContainer.appendChild(mockElement);
|
|
770
|
+
|
|
771
|
+
jest.spyOn(clippingContainer, 'getBoundingClientRect').mockReturnValue({
|
|
772
|
+
top: 100,
|
|
773
|
+
left: 100,
|
|
774
|
+
bottom: 500,
|
|
775
|
+
right: 500,
|
|
776
|
+
width: 400,
|
|
777
|
+
height: 400,
|
|
778
|
+
} as DOMRect);
|
|
779
|
+
|
|
780
|
+
jest.spyOn(mockElement, 'getBoundingClientRect').mockReturnValue({
|
|
781
|
+
top: 50,
|
|
782
|
+
left: 50,
|
|
783
|
+
bottom: 700,
|
|
784
|
+
right: 700,
|
|
785
|
+
width: 650,
|
|
786
|
+
height: 650,
|
|
787
|
+
} as DOMRect);
|
|
788
|
+
|
|
789
|
+
const result = calculateVisibleElementData(mockElement, true);
|
|
790
|
+
|
|
791
|
+
expect(result).toEqual({
|
|
792
|
+
top: 50,
|
|
793
|
+
height: 400,
|
|
794
|
+
left: 50,
|
|
795
|
+
width: 400,
|
|
796
|
+
});
|
|
797
|
+
});
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
describe('getScrollableAncestors', () => {
|
|
801
|
+
it('should return an empty list when element is missing', () => {
|
|
802
|
+
expect(getScrollableAncestors(null as unknown as HTMLElement)).toEqual([]);
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
it('should find scrollable ancestors inside a shadow root', () => {
|
|
806
|
+
const host = document.createElement('div');
|
|
807
|
+
document.body.appendChild(host);
|
|
808
|
+
|
|
809
|
+
const shadow = host.attachShadow({ mode: 'open' });
|
|
810
|
+
const scrollContainer = document.createElement('div');
|
|
811
|
+
scrollContainer.style.overflow = 'auto';
|
|
812
|
+
const embedTarget = document.createElement('div');
|
|
813
|
+
const iframe = document.createElement('iframe');
|
|
814
|
+
|
|
815
|
+
shadow.appendChild(scrollContainer);
|
|
816
|
+
scrollContainer.appendChild(embedTarget);
|
|
817
|
+
embedTarget.appendChild(iframe);
|
|
818
|
+
|
|
819
|
+
expect(getScrollableAncestors(iframe)).toEqual([scrollContainer]);
|
|
820
|
+
|
|
821
|
+
host.remove();
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
it('should ignore ancestors when computed style is unavailable', () => {
|
|
825
|
+
const parent = document.createElement('div');
|
|
826
|
+
const iframe = document.createElement('iframe');
|
|
827
|
+
parent.appendChild(iframe);
|
|
828
|
+
|
|
829
|
+
const getComputedStyleSpy = jest
|
|
830
|
+
.spyOn(window, 'getComputedStyle')
|
|
831
|
+
.mockReturnValue(null as unknown as CSSStyleDeclaration);
|
|
832
|
+
|
|
833
|
+
expect(getScrollableAncestors(iframe)).toEqual([]);
|
|
834
|
+
|
|
835
|
+
getComputedStyleSpy.mockRestore();
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
describe('getClippingAncestors', () => {
|
|
840
|
+
it('should return an empty list when element is missing', () => {
|
|
841
|
+
expect(getClippingAncestors(null as unknown as HTMLElement)).toEqual([]);
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
it('should include scrollable and non-scroll clipping ancestors', () => {
|
|
845
|
+
const scrollContainer = document.createElement('div');
|
|
846
|
+
scrollContainer.style.overflow = 'auto';
|
|
847
|
+
const clippingContainer = document.createElement('div');
|
|
848
|
+
clippingContainer.style.overflow = 'hidden';
|
|
849
|
+
const iframe = document.createElement('iframe');
|
|
850
|
+
|
|
851
|
+
scrollContainer.appendChild(clippingContainer);
|
|
852
|
+
clippingContainer.appendChild(iframe);
|
|
853
|
+
|
|
854
|
+
expect(getClippingAncestors(iframe)).toEqual([clippingContainer, scrollContainer]);
|
|
855
|
+
});
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
describe('getEffectiveClippingAncestors', () => {
|
|
859
|
+
it('should return an empty list when element is missing', () => {
|
|
860
|
+
expect(getEffectiveClippingAncestors(null as unknown as HTMLElement)).toEqual([]);
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
it('should ignore overflow ancestors that do not clip the element', () => {
|
|
864
|
+
const clippingContainer = document.createElement('div');
|
|
865
|
+
clippingContainer.style.overflow = 'hidden';
|
|
866
|
+
const iframe = document.createElement('iframe');
|
|
867
|
+
|
|
868
|
+
clippingContainer.appendChild(iframe);
|
|
869
|
+
|
|
870
|
+
jest.spyOn(clippingContainer, 'getBoundingClientRect').mockReturnValue({
|
|
871
|
+
top: 100,
|
|
872
|
+
left: 100,
|
|
873
|
+
bottom: 700,
|
|
874
|
+
right: 700,
|
|
875
|
+
width: 600,
|
|
876
|
+
height: 600,
|
|
877
|
+
} as DOMRect);
|
|
878
|
+
jest.spyOn(iframe, 'getBoundingClientRect').mockReturnValue({
|
|
879
|
+
top: 200,
|
|
880
|
+
left: 200,
|
|
881
|
+
bottom: 400,
|
|
882
|
+
right: 400,
|
|
883
|
+
width: 200,
|
|
884
|
+
height: 200,
|
|
885
|
+
} as DOMRect);
|
|
886
|
+
|
|
887
|
+
expect(getEffectiveClippingAncestors(iframe)).toEqual([]);
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
it('should include overflow ancestors that clip the element', () => {
|
|
891
|
+
const clippingContainer = document.createElement('div');
|
|
892
|
+
clippingContainer.style.overflow = 'hidden';
|
|
893
|
+
const iframe = document.createElement('iframe');
|
|
894
|
+
|
|
895
|
+
clippingContainer.appendChild(iframe);
|
|
896
|
+
|
|
897
|
+
jest.spyOn(clippingContainer, 'getBoundingClientRect').mockReturnValue({
|
|
898
|
+
top: 100,
|
|
899
|
+
left: 100,
|
|
900
|
+
bottom: 500,
|
|
901
|
+
right: 500,
|
|
902
|
+
width: 400,
|
|
903
|
+
height: 400,
|
|
904
|
+
} as DOMRect);
|
|
905
|
+
jest.spyOn(iframe, 'getBoundingClientRect').mockReturnValue({
|
|
906
|
+
top: 50,
|
|
907
|
+
left: 50,
|
|
908
|
+
bottom: 700,
|
|
909
|
+
right: 700,
|
|
910
|
+
width: 650,
|
|
911
|
+
height: 650,
|
|
912
|
+
} as DOMRect);
|
|
913
|
+
|
|
914
|
+
expect(getEffectiveClippingAncestors(iframe)).toEqual([clippingContainer]);
|
|
915
|
+
});
|
|
720
916
|
});
|
|
721
917
|
|
|
722
918
|
describe('formatTemplate', () => {
|
package/src/utils.ts
CHANGED
|
@@ -518,22 +518,141 @@ export const handleExitPresentMode = async (): Promise<void> => {
|
|
|
518
518
|
logger.warn('Exit fullscreen API is not supported by this browser.');
|
|
519
519
|
};
|
|
520
520
|
|
|
521
|
-
|
|
521
|
+
const scrollableOverflowPattern = /(auto|scroll|overlay)/;
|
|
522
|
+
const clippingOverflowPattern = /(auto|scroll|overlay|hidden|clip)/;
|
|
523
|
+
|
|
524
|
+
const getParentElementAcrossShadowRoot = (element: HTMLElement): HTMLElement | null => {
|
|
525
|
+
if (element.parentElement) {
|
|
526
|
+
return element.parentElement;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const rootNode = element.getRootNode?.();
|
|
530
|
+
if (typeof ShadowRoot !== 'undefined' && rootNode instanceof ShadowRoot) {
|
|
531
|
+
return rootNode.host as HTMLElement;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return null;
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
const hasMatchingOverflow = (element: HTMLElement, overflowPattern: RegExp) => {
|
|
538
|
+
const style = window.getComputedStyle(element);
|
|
539
|
+
return style ? overflowPattern.test(style.overflow + style.overflowX + style.overflowY) : false;
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
export const getScrollableAncestors = (element: HTMLElement) => {
|
|
543
|
+
const ancestors: HTMLElement[] = [];
|
|
544
|
+
if (!element) {
|
|
545
|
+
return ancestors;
|
|
546
|
+
}
|
|
547
|
+
let parent = getParentElementAcrossShadowRoot(element);
|
|
548
|
+
|
|
549
|
+
while (parent && parent !== document.body && parent !== document.documentElement) {
|
|
550
|
+
if (hasMatchingOverflow(parent, scrollableOverflowPattern)) {
|
|
551
|
+
ancestors.push(parent);
|
|
552
|
+
}
|
|
553
|
+
parent = getParentElementAcrossShadowRoot(parent);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return ancestors;
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
export const getClippingAncestors = (element: HTMLElement) => {
|
|
560
|
+
const ancestors: HTMLElement[] = [];
|
|
561
|
+
if (!element) {
|
|
562
|
+
return ancestors;
|
|
563
|
+
}
|
|
564
|
+
let parent = getParentElementAcrossShadowRoot(element);
|
|
565
|
+
|
|
566
|
+
while (parent && parent !== document.body && parent !== document.documentElement) {
|
|
567
|
+
if (hasMatchingOverflow(parent, clippingOverflowPattern)) {
|
|
568
|
+
ancestors.push(parent);
|
|
569
|
+
}
|
|
570
|
+
parent = getParentElementAcrossShadowRoot(parent);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return ancestors;
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
const getIntersectedRect = (
|
|
577
|
+
rect: Pick<DOMRect, 'top' | 'left' | 'bottom' | 'right'>,
|
|
578
|
+
clipRect: Pick<DOMRect, 'top' | 'left' | 'bottom' | 'right'>,
|
|
579
|
+
) => ({
|
|
580
|
+
top: Math.max(rect.top, clipRect.top),
|
|
581
|
+
left: Math.max(rect.left, clipRect.left),
|
|
582
|
+
bottom: Math.min(rect.bottom, clipRect.bottom),
|
|
583
|
+
right: Math.min(rect.right, clipRect.right),
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
const isSameVisibleRect = (
|
|
587
|
+
rectA: ReturnType<typeof getIntersectedRect>,
|
|
588
|
+
rectB: ReturnType<typeof getIntersectedRect>,
|
|
589
|
+
) => rectA.top === rectB.top
|
|
590
|
+
&& rectA.left === rectB.left
|
|
591
|
+
&& rectA.bottom === rectB.bottom
|
|
592
|
+
&& rectA.right === rectB.right;
|
|
593
|
+
|
|
594
|
+
export const getEffectiveClippingAncestors = (element: HTMLElement) => {
|
|
595
|
+
if (!element) {
|
|
596
|
+
return [];
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const elementRect = element.getBoundingClientRect();
|
|
600
|
+
let clipRect = {
|
|
601
|
+
top: 0,
|
|
602
|
+
left: 0,
|
|
603
|
+
bottom: window.innerHeight,
|
|
604
|
+
right: window.innerWidth,
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
return getClippingAncestors(element).filter((ancestor) => {
|
|
608
|
+
const currentVisibleRect = getIntersectedRect(elementRect, clipRect);
|
|
609
|
+
const nextClipRect = getIntersectedRect(clipRect, ancestor.getBoundingClientRect());
|
|
610
|
+
const nextVisibleRect = getIntersectedRect(elementRect, nextClipRect);
|
|
611
|
+
const clipsElement = !isSameVisibleRect(currentVisibleRect, nextVisibleRect);
|
|
612
|
+
clipRect = nextClipRect;
|
|
613
|
+
return clipsElement;
|
|
614
|
+
});
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
export const calculateVisibleElementData = (
|
|
618
|
+
element: HTMLElement,
|
|
619
|
+
useClippingAncestors = false,
|
|
620
|
+
) => {
|
|
621
|
+
if (!element) {
|
|
622
|
+
return {
|
|
623
|
+
top: 0,
|
|
624
|
+
height: 0,
|
|
625
|
+
left: 0,
|
|
626
|
+
width: 0,
|
|
627
|
+
};
|
|
628
|
+
}
|
|
522
629
|
const rect = element.getBoundingClientRect();
|
|
523
630
|
|
|
524
|
-
|
|
525
|
-
|
|
631
|
+
let clipTop = 0;
|
|
632
|
+
let clipLeft = 0;
|
|
633
|
+
let clipBottom = window.innerHeight;
|
|
634
|
+
let clipRight = window.innerWidth;
|
|
635
|
+
|
|
636
|
+
if (useClippingAncestors) {
|
|
637
|
+
getEffectiveClippingAncestors(element).forEach((ancestor) => {
|
|
638
|
+
const ancestorRect = ancestor.getBoundingClientRect();
|
|
639
|
+
clipTop = Math.max(clipTop, ancestorRect.top);
|
|
640
|
+
clipLeft = Math.max(clipLeft, ancestorRect.left);
|
|
641
|
+
clipBottom = Math.min(clipBottom, ancestorRect.bottom);
|
|
642
|
+
clipRight = Math.min(clipRight, ancestorRect.right);
|
|
643
|
+
});
|
|
644
|
+
}
|
|
526
645
|
|
|
527
|
-
const frameRelativeTop = Math.max(rect.top,
|
|
528
|
-
const frameRelativeLeft = Math.max(rect.left,
|
|
646
|
+
const frameRelativeTop = Math.max(rect.top, clipTop);
|
|
647
|
+
const frameRelativeLeft = Math.max(rect.left, clipLeft);
|
|
529
648
|
|
|
530
|
-
const frameRelativeBottom = Math.min(
|
|
531
|
-
const frameRelativeRight = Math.min(
|
|
649
|
+
const frameRelativeBottom = Math.min(clipBottom, rect.bottom);
|
|
650
|
+
const frameRelativeRight = Math.min(clipRight, rect.right);
|
|
532
651
|
|
|
533
652
|
const data = {
|
|
534
|
-
top: Math.max(0, rect.top
|
|
653
|
+
top: Math.max(0, clipTop - rect.top),
|
|
535
654
|
height: Math.max(0, frameRelativeBottom - frameRelativeTop),
|
|
536
|
-
left: Math.max(0, rect.left
|
|
655
|
+
left: Math.max(0, clipLeft - rect.left),
|
|
537
656
|
width: Math.max(0, frameRelativeRight - frameRelativeLeft),
|
|
538
657
|
};
|
|
539
658
|
|