Skip to content

Commit ce30314

Browse files
authored
[MOB-11427] Add maxWidth to getInAppMessages payload (#491)
* [MOB-11427] Add maxWidth to getinappmessages payload * [MOB-11427] Include ESLint as workspace formatter * Revert "[MOB-11427] Include ESLint as workspace formatter" This reverts commit 63639ea. * [MOB-11427] Update tests and refactor * [MOB-11427] Add test * [MOB-11427] Update README
1 parent 16710eb commit ce30314

File tree

5 files changed

+211
-179
lines changed

5 files changed

+211
-179
lines changed

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,12 +2360,24 @@ For example:
23602360
- If your in-app is positioned in the center and your browser if at 700px, your
23612361
in-app message will grow to take up 100% of the screen.
23622362

2363-
This chart also implies that yout in-app message is taking 100% of its container.
2363+
This chart also implies that your in-app message is taking 100% of its container.
23642364
Your results may vary if you add, for example, a `max-width: 200px` CSS rule to
2365-
your message HTML.
2365+
your message HTML, as it would not apply to the enclosing iframe.
23662366

2367-
Regardless of how you write your CSS, these rules take effect. So, when creating
2368-
an in-app message, it is best to stick with percentage-based CSS widths.
2367+
For Center, Top-Right, and Bottom-Right positions, you can set a custom `maxWidth`
2368+
by including it in your getInAppMessages payload like this:
2369+
2370+
```ts
2371+
const { request } = getInAppMessages({
2372+
count: 20,
2373+
packageName: 'my-website',
2374+
maxWidth: '900px'
2375+
});
2376+
```
2377+
2378+
`maxWidth` accepts any valid CSS max-width value (e.g., px, em, %, ch).
2379+
It is optional—-most in-app messages render well with default sizing, so set it
2380+
only if needed for your use case.
23692381

23702382
## How do I add custom callbacks to handle link clicks on in-app and embedded messages?
23712383

src/inapp/inapp.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export function getInAppMessages(
9191
delete dupedPayload.animationDuration;
9292
delete dupedPayload.handleLinks;
9393
delete dupedPayload.closeButton;
94+
delete dupedPayload.maxWidth;
9495

9596
if (options?.display) {
9697
addStyleSheet(document, ANIMATION_STYLESHEET(payload.animationDuration));
@@ -159,15 +160,17 @@ export function getInAppMessages(
159160
};
160161

161162
/* add the message's html to an iframe and paint it to the DOM */
162-
return paintIFrame(
163-
activeMessage.content.html as string,
164-
messagePosition,
163+
return paintIFrame({
164+
html: activeMessage.content.html as string,
165+
position: messagePosition,
165166
shouldAnimate,
166-
payload.onOpenScreenReaderMessage || 'in-app iframe message opened',
167-
payload.topOffset,
168-
payload.bottomOffset,
169-
payload.rightOffset
170-
).then((activeIframe) => {
167+
srMessage:
168+
payload.onOpenScreenReaderMessage || 'in-app iframe message opened',
169+
topOffset: payload.topOffset,
170+
bottomOffset: payload.bottomOffset,
171+
rightOffset: payload.rightOffset,
172+
maxWidth: payload.maxWidth
173+
}).then((activeIframe) => {
171174
const activeIframeDocument = activeIframe?.contentDocument;
172175

173176
const throttledResize =

src/inapp/tests/utils.test.ts

Lines changed: 104 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -717,147 +717,157 @@ describe('Utils', () => {
717717
});
718718

719719
describe('painting the iframe', () => {
720+
const defaultStyles = {
721+
position: 'fixed',
722+
left: '0%',
723+
right: '0%',
724+
top: '0%',
725+
bottom: '0%',
726+
zIndex: '9999',
727+
width: '100%',
728+
maxHeight: '95vh',
729+
maxWidth: '100%'
730+
};
731+
732+
const checkStyles = (
733+
styles: CSSStyleDeclaration,
734+
overrides?: Partial<typeof defaultStyles> & { height?: string }
735+
) => {
736+
Object.entries(defaultStyles).forEach(([key, value]) => {
737+
const styleValue = styles[key as keyof typeof styles];
738+
expect(styleValue).toBe(
739+
overrides && key in overrides
740+
? overrides[key as keyof typeof overrides]
741+
: value
742+
);
743+
});
744+
};
745+
720746
it('should paint the iframe in the center of the screen', async () => {
721-
const iframe = await paintIFrame(
722-
mockMarkup,
723-
DisplayPosition.Center,
724-
false,
725-
'hi'
726-
);
747+
const iframe = await paintIFrame({
748+
html: mockMarkup,
749+
position: DisplayPosition.Center,
750+
srMessage: 'hi'
751+
});
727752
jest.advanceTimersByTime(2000);
728753

729754
/* speed up time to past the setTimeout */
730755
const styles = getComputedStyle(iframe);
731-
expect(styles.position).toBe('fixed');
732-
expect(styles.left).toBe('0%');
733-
expect(styles.right).toBe('0%');
734-
expect(styles.top).toBe('0%');
735-
expect(styles.bottom).toBe('0%');
736-
expect(styles.zIndex).toBe('9999');
737-
expect(styles.width).toBe('100%');
738-
expect(styles.maxHeight).toBe('95vh');
756+
checkStyles(styles);
757+
});
758+
759+
it('should paint the iframe with custom maxWidth', async () => {
760+
const { Center, TopRight, BottomRight } = DisplayPosition;
761+
[Center, TopRight, BottomRight].forEach(async (position) => {
762+
const iframe = await paintIFrame({
763+
html: mockMarkup,
764+
position,
765+
maxWidth: '350px'
766+
});
767+
jest.advanceTimersByTime(2000);
768+
const styles = getComputedStyle(iframe);
769+
expect(styles.maxWidth).toBe('350px');
770+
});
739771
});
740772

741773
it('should paint the iframe in the top-right of the screen', async () => {
742-
const iframe = await paintIFrame(
743-
mockMarkup,
744-
DisplayPosition.TopRight,
745-
false,
746-
'hi'
747-
);
774+
const iframe = await paintIFrame({
775+
html: mockMarkup,
776+
position: DisplayPosition.TopRight,
777+
srMessage: 'hi'
778+
});
748779
jest.advanceTimersByTime(2000);
749780

750781
/* speed up time to past the setTimeout */
751782
const styles = getComputedStyle(iframe);
752-
expect(styles.position).toBe('fixed');
753-
expect(styles.left).toBe('');
754-
expect(styles.right).toBe('0%');
755-
expect(styles.top).toBe('0%');
756-
expect(styles.bottom).toBe('');
757-
expect(styles.zIndex).toBe('9999');
758-
expect(styles.width).toBe('100%');
759-
expect(styles.maxHeight).toBe('95vh');
783+
checkStyles(styles, { left: '', bottom: '' });
760784
});
761785

762786
it('should paint the iframe in the bottom-right of the screen', async () => {
763-
const iframe = await paintIFrame(
764-
mockMarkup,
765-
DisplayPosition.BottomRight,
766-
false,
767-
'hi'
768-
);
787+
const iframe = await paintIFrame({
788+
html: mockMarkup,
789+
position: DisplayPosition.BottomRight,
790+
srMessage: 'hi'
791+
});
769792
jest.advanceTimersByTime(2000);
770793

771794
/* speed up time to past the setTimeout */
772795
const styles = getComputedStyle(iframe);
773-
expect(styles.position).toBe('fixed');
774-
expect(styles.left).toBe('');
775-
expect(styles.right).toBe('0%');
776-
expect(styles.bottom).toBe('0%');
777-
expect(styles.top).toBe('');
778-
expect(styles.zIndex).toBe('9999');
779-
expect(styles.width).toBe('100%');
780-
expect(styles.maxHeight).toBe('95vh');
796+
checkStyles(styles, { left: '', top: '' });
781797
});
782798

783799
it('should paint the iframe full-screen', async () => {
784-
const iframe = await paintIFrame(
785-
mockMarkup,
786-
DisplayPosition.Full,
787-
false,
788-
''
789-
);
800+
const iframe = await paintIFrame({
801+
html: mockMarkup,
802+
position: DisplayPosition.Full
803+
});
790804
jest.advanceTimersByTime(2000);
791805

792806
/* speed up time to past the setTimeout */
793807
const styles = getComputedStyle(iframe);
794-
expect(styles.position).toBe('fixed');
795-
expect(styles.left).toBe('0%');
796-
expect(styles.right).toBe('');
797-
expect(styles.bottom).toBe('');
798-
expect(styles.top).toBe('0%');
799-
expect(styles.zIndex).toBe('9999');
800-
expect(styles.height).toBe('100%');
801-
expect(styles.width).toBe('100%');
802-
expect(styles.maxHeight).toBe('');
808+
checkStyles(styles, {
809+
right: '',
810+
bottom: '',
811+
height: '100%',
812+
maxHeight: ''
813+
});
803814
});
804815

805816
it('should paint TopRight iframes with custom offsets', async () => {
806-
const iframe = await paintIFrame(
807-
mockMarkup,
808-
DisplayPosition.TopRight,
809-
false,
810-
'',
811-
'10px',
812-
'10px',
813-
'10px'
814-
);
817+
const iframe = await paintIFrame({
818+
html: mockMarkup,
819+
position: DisplayPosition.TopRight,
820+
topOffset: '10px',
821+
bottomOffset: '10px',
822+
rightOffset: '10px'
823+
});
815824
jest.advanceTimersByTime(2000);
816825

817826
/* speed up time to past the setTimeout */
818827
const styles = getComputedStyle(iframe);
819-
expect(styles.position).toBe('fixed');
820-
expect(styles.left).toBe('');
821-
expect(styles.right).toBe('10px');
822-
expect(styles.bottom).toBe('');
823-
expect(styles.top).toBe('10px');
824-
expect(styles.zIndex).toBe('9999');
825-
expect(styles.width).toBe('100%');
826-
expect(styles.maxHeight).toBe('95vh');
828+
checkStyles(styles, {
829+
left: '',
830+
right: '10px',
831+
bottom: '',
832+
top: '10px'
833+
});
827834
});
828835

829836
it('should paint BottomRight iframes with custom offsets', async () => {
830-
const iframe = await paintIFrame(
831-
mockMarkup,
832-
DisplayPosition.BottomRight,
833-
false,
834-
'',
835-
'10px',
836-
'10px',
837-
'10px'
838-
);
837+
const iframe = await paintIFrame({
838+
html: mockMarkup,
839+
position: DisplayPosition.BottomRight,
840+
topOffset: '10px',
841+
bottomOffset: '10px',
842+
rightOffset: '10px'
843+
});
839844
jest.advanceTimersByTime(2000);
840845

841846
/* speed up time to past the setTimeout */
842847
const styles = getComputedStyle(iframe);
843-
expect(styles.position).toBe('fixed');
844-
expect(styles.left).toBe('');
845-
expect(styles.right).toBe('10px');
846-
expect(styles.bottom).toBe('10px');
847-
expect(styles.top).toBe('');
848-
expect(styles.zIndex).toBe('9999');
849-
expect(styles.width).toBe('100%');
850-
expect(styles.maxHeight).toBe('95vh');
848+
checkStyles(styles, {
849+
left: '',
850+
right: '10px',
851+
bottom: '10px',
852+
top: ''
853+
});
851854
});
852855

853856
it('should call srSpeak if screen reader text passed', async () => {
854-
await paintIFrame(mockMarkup, DisplayPosition.Center, false, 'hi');
857+
await paintIFrame({
858+
html: mockMarkup,
859+
position: DisplayPosition.Center,
860+
srMessage: 'hi'
861+
});
855862

856863
expect((srSpeak as any).mock.calls.length).toBe(1);
857864
});
858865

859866
it('should not call srSpeak if no screen reader text passed', async () => {
860-
await paintIFrame(mockMarkup, DisplayPosition.Center, false);
867+
await paintIFrame({
868+
html: mockMarkup,
869+
position: DisplayPosition.Center
870+
});
861871

862872
expect((srSpeak as any).mock.calls.length).toBe(0);
863873
});
@@ -869,6 +879,7 @@ describe('Utils', () => {
869879

870880
expect(el.getAttribute('aria-label')).toBe('hello');
871881
expect(el.getAttribute('role')).toBe('button');
882+
// eslint-disable-next-line no-script-url
872883
expect(el.getAttribute('href')).toBe('javascript:undefined');
873884
});
874885

0 commit comments

Comments
 (0)