Skip to content

Commit

Permalink
Support fullscreen mode in Q search bar embedding
Browse files Browse the repository at this point in the history
  • Loading branch information
Joey Ashcroft authored and bwelkin committed Apr 19, 2023
1 parent 2850125 commit dff55da
Show file tree
Hide file tree
Showing 10 changed files with 509 additions and 466 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,7 @@
**2.1.0**
* Support fullscreen mode in Q search bar embedding
* Minor bug fixes

**2.0.3**
* Minor bug fixes

Expand Down
10 changes: 5 additions & 5 deletions README.md
Expand Up @@ -19,7 +19,7 @@ Amazon QuickSight offers four different embedding experiences with options for u
**Option 1:** Use the Amazon QuickSight Embedding SDK in the browser:
```html
...
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.0.3/dist/quicksight-embedding-js-sdk.min.js"></script>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.1.0/dist/quicksight-embedding-js-sdk.min.js"></script>
<script type="text/javascript">
const onLoad = async () => {
const embeddingContext = await QuickSightEmbedding.createEmbeddingContext();
Expand Down Expand Up @@ -446,7 +446,7 @@ export interface BaseFrame {

<head>
<title>Dashboard Embedding Example</title>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.0.3/dist/quicksight-embedding-js-sdk.min.js"></script>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.1.0/dist/quicksight-embedding-js-sdk.min.js"></script>
<script type="text/javascript">
const embedDashboard = async() => {
const {
Expand Down Expand Up @@ -816,7 +816,7 @@ export interface BaseFrame {

<head>
<title>Visual Embedding Example</title>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.0.3/dist/quicksight-embedding-js-sdk.min.js"></script>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.1.0/dist/quicksight-embedding-js-sdk.min.js"></script>
<script type="text/javascript">
const embedVisual = async() => {
const {
Expand Down Expand Up @@ -1037,7 +1037,7 @@ export interface BaseFrame {

<head>
<title>Console Embedding Example</title>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.0.3/dist/quicksight-embedding-js-sdk.min.js"></script>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.1.0/dist/quicksight-embedding-js-sdk.min.js"></script>
<script type="text/javascript">
const embedConsole = async() => {
const {
Expand Down Expand Up @@ -1155,7 +1155,7 @@ export interface BaseFrame {

<head>
<title>Q Search Bar Embedding Example</title>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.0.3/dist/quicksight-embedding-js-sdk.min.js"></script>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk@2.1.0/dist/quicksight-embedding-js-sdk.min.js"></script>
<script type="text/javascript">
const embedQSearchBar = async() => {
const {
Expand Down
788 changes: 387 additions & 401 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
@@ -1,7 +1,7 @@
{
"name": "amazon-quicksight-embedding-sdk",
"description": "JS SDK for embedding Amazon QuickSight",
"version": "2.0.3",
"version": "2.1.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
Expand Down
76 changes: 40 additions & 36 deletions src/commons/createIframe.ts
@@ -1,46 +1,53 @@
import {CreateIframeOptions, CreatePostRequestOptions, EmbeddingIFrameElement, PostRequest} from '../types';

const createSvgElement = (tagName: string, attributes: Record<string, string>, children: Element[] = []) => {
const createSvgElement = (tagName: string, attributes: Record<string, string>, styles: Record<string, string> = {}, children: Element[] = []) => {
const element = document.createElementNS('http://www.w3.org/2000/svg', tagName);
Object.entries(attributes).forEach(([name, value]) => element.setAttribute(name, value));
Object.entries(styles).forEach(([name, value]) => element.style.setProperty(name, value));
children.forEach(child => element.appendChild(child));
return element;
};

const circles: Element[] = [1, 2, 3].map(i => {
const animate = createSvgElement('animate', {
attributeName: 'opacity',
dur: '1s',
values: '0;1;0',
repeatCount: 'indefinite',
begin: `${i / 10.0}`,
const createLoaderSVG = () => {
const circles: Element[] = [1, 2, 3].map(i => {
const animate = createSvgElement('animate', {
attributeName: 'opacity',
dur: '1s',
values: '0;1;0',
repeatCount: 'indefinite',
begin: `${i / 10.0}`,
});
const circle = createSvgElement(
'circle',
{
fill: '#ccc',
stroke: 'none',
cx: `${i * 20 - 14}`,
cy: '50',
r: '6',
},
undefined,
[animate]
);
return circle;
});
const circle = createSvgElement(
'circle',

return createSvgElement(
'svg',
{
version: '1.1',
x: '0px',
y: '0px',
viewBox: '0 0 100 100',
'enable-background': 'new 0 0 0 0',
},
{
fill: '#ccc',
stroke: 'none',
cx: `${i * 20 - 14}`,
cy: '50',
r: '6',
width: '100px',
height: '100px',
},
[animate]
circles
);
return circle;
});

const loaderSVG = createSvgElement(
'svg',
{
version: '1.1',
x: '0px',
y: '0px',
viewBox: '0 0 100 100',
'enable-background': 'new 0 0 0 0',
style: 'width:100px; height:100px;',
},
circles
);
};

const createPostRequest = (postRequestOptions: CreatePostRequestOptions): PostRequest => {
const {src, container, target, payload} = postRequestOptions;
Expand Down Expand Up @@ -95,6 +102,7 @@ const createIframe = (options: CreateIframeOptions): EmbeddingIFrameElement | nu
if (typeof withIframePlaceholder !== 'boolean') {
iframePlaceholder.appendChild(withIframePlaceholder);
} else {
const loaderSVG = createLoaderSVG();
iframePlaceholder.appendChild(loaderSVG);
}
container.appendChild(iframePlaceholder);
Expand Down Expand Up @@ -126,11 +134,7 @@ const createIframe = (options: CreateIframeOptions): EmbeddingIFrameElement | nu
iframe.style.position = 'absolute';
}

try {
container.appendChild(iframe);
} catch (error) {
return null;
}
container.appendChild(iframe);

let postRequest: PostRequest;

Expand Down
2 changes: 1 addition & 1 deletion src/commons/index.ts
Expand Up @@ -4,7 +4,7 @@
import {encode} from 'punycode';
import {BuildExperienceUrlOptions, TargetedMessageEvent, InternalExperience, PostMessageEvent, UrlInfo, ParameterValue} from '../types';

const SDK_VERSION = '2.0.3';
const SDK_VERSION = '2.1.0';

const FRAME_TIMEOUT = 60000;

Expand Down
2 changes: 2 additions & 0 deletions src/enums.ts
Expand Up @@ -11,6 +11,8 @@ export enum InfoMessageEventName {
Q_SEARCH_CLOSED = 'Q_SEARCH_CLOSED',
Q_SEARCH_OPENED = 'Q_SEARCH_OPENED',
Q_SEARCH_SIZE_CHANGED = 'Q_SEARCH_SIZE_CHANGED',
Q_SEARCH_ENTERED_FULLSCREEN = 'Q_SEARCH_ENTERED_FULLSCREEN',
Q_SEARCH_EXITED_FULLSCREEN = 'Q_SEARCH_EXITED_FULLSCREEN',
}

export enum SetterMessageEventName {
Expand Down
26 changes: 13 additions & 13 deletions src/experiences/createExperienceFrame.ts
Expand Up @@ -210,18 +210,18 @@ const createExperienceFrame = (
},
});

experienceIframe = createIframe({
id: experienceIdentifier,
src: _url,
width,
height,
container: _container,
onLoad: onLoadHandler,
withIframePlaceholder,
className,
});

if (!experienceIframe) {
try {
experienceIframe = createIframe({
id: experienceIdentifier,
src: _url,
width,
height,
container: _container,
onLoad: onLoadHandler,
withIframePlaceholder,
className,
});
} catch (error) {
_onChange({
eventName: ChangeEventName.FRAME_NOT_CREATED,
eventLevel: ChangeEventLevel.ERROR,
Expand All @@ -230,7 +230,7 @@ const createExperienceFrame = (
experience: internalExperience,
},
});
throw new Error('Failed to create the frame');
throw error;
}

_onChange({
Expand Down
56 changes: 47 additions & 9 deletions src/experiences/qsearch/createQSearchFrame.ts
Expand Up @@ -11,12 +11,15 @@ import {
ResponseMessage,
SimpleMessageEvent,
TransformedQSearchContentOptions,
FrameStyles,
} from '../../types';
import {ChangeEventLevel, MessageEventName, ChangeEventName} from '../../enums';
import createExperienceFrame from '../createExperienceFrame';
import {extractQSearchExperienceFromUrl, getQSearchExperienceIdentifier} from '.';
import {buildInternalExperienceInfo} from '../commons';

const MAX_Z_INDEX = '2147483647';

const createQSearchFrame = (
frameOptions: FrameOptions,
contentOptions: QSearchContentOptions,
Expand All @@ -25,6 +28,7 @@ const createQSearchFrame = (
): QSearchFrame => {
const {url, onChange} = frameOptions;
const {contextId} = controlOptions || {};
let frameStyles: FrameStyles;

if (!url) {
const message = 'Url is required for the experience';
Expand Down Expand Up @@ -55,15 +59,49 @@ const createQSearchFrame = (
getQSearchExperienceIdentifier
);

const interceptMessage = (messageEvent: SimpleMessageEvent, metadata: ExperienceFrameMetadata) => {
// Intercepting onMessage
// if the resizeHeightOnSizeChangedEvent is true, upon receiving SIZE_CHANGED message, update the height of the iframe
if (['Q_SEARCH_OPENED', 'Q_SEARCH_CLOSED'].includes(messageEvent.eventName)) {
metadata.frame.style.height = `${messageEvent.message.height}px`;
} else if (messageEvent.eventName === MessageEventName.CONTENT_LOADED) {
window.addEventListener('click', event => {
!experienceFrame.frame.contains(event.target as Node) && _close();
});
const interceptMessage = (
messageEvent: SimpleMessageEvent,
metadata: ExperienceFrameMetadata
) => {
switch (messageEvent.eventName) {
case MessageEventName.Q_SEARCH_OPENED:
case MessageEventName.Q_SEARCH_CLOSED: {
metadata.frame.style.height = `${messageEvent.message.height}px`;
break;
}
case MessageEventName.CONTENT_LOADED: {
window.addEventListener('click', event => {
!experienceFrame.frame.contains(event.target as Node) &&
_close();
});
break;
}
case MessageEventName.Q_SEARCH_ENTERED_FULLSCREEN: {
frameStyles = {
position: metadata.frame.style.position,
top: metadata.frame.style.top,
left: metadata.frame.style.left,
zIndex: metadata.frame.style.zIndex,
width: metadata.frame.style.width,
height: metadata.frame.style.height,
};
metadata.frame.style.position = 'fixed';
metadata.frame.style.top = '0px';
metadata.frame.style.left = '0px';
metadata.frame.style.zIndex = MAX_Z_INDEX;
metadata.frame.style.width = '100vw';
metadata.frame.style.height = '100vh';
break;
}
case MessageEventName.Q_SEARCH_EXITED_FULLSCREEN: {
metadata.frame.style.position = frameStyles.position;
metadata.frame.style.top = frameStyles.top;
metadata.frame.style.left = frameStyles.left;
metadata.frame.style.zIndex = frameStyles.zIndex;
metadata.frame.style.width = frameStyles.width;
metadata.frame.style.height = frameStyles.height;
break;
}
}
};

Expand Down
9 changes: 9 additions & 0 deletions src/types.ts
Expand Up @@ -339,6 +339,15 @@ export type FrameOptions = {
onChange?: SimpleChangeEventHandler;
};

export type FrameStyles = {
position: string,
top: string,
left: string,
zIndex: string,
width: string,
height: string,
};

export type UrlInfo = {
guid: string;
host: string;
Expand Down

0 comments on commit dff55da

Please sign in to comment.