-
Notifications
You must be signed in to change notification settings - Fork 7
Advanced Topics
Jsx For Apl provides contracts for APL Commands. Therefore it leverages command declarations within typescript usage. The set of usable commands interfaces can be found under Which APL Components does Jsx for Apl provide section.
The following sample demonstrates the usage of AnimateItem
command inside onMount
property.
// FruitApl.tsx
import * as React from "react";
import { Frame, Container, Text, Image, APL, MainTemplate, Command } from "ask-sdk-jsx-for-apl";
export class FruitApl extends React.Component<{ fruit: object }> {
public render() {
return (
<APL>
<MainTemplate>
<Frame width="100vw" height="100vh" backgroundColor="rgb(22,147,165)">
<Container
width="100vw"
height="100vh"
alignItems="center"
justifyContent="spaceAround"
>
<Text text="${this.props.fruit.title}" fontSize="50px" color="rgb(251,184,41)" />
<Image
source="${this.props.fruit.image}"
height="60vh"
width="30vh"
scale="best-fit"
onMount={[this.buildAnimateCommand()]}
/>
</Container>
</Frame>
</MainTemplate>
</APL>
);
}
private buildAnimateCommand(): Command {
const command: Command = {
type: "AnimateItem",
duration: 600,
easing: "ease-in-out",
value: [
{
property: "opacity",
from: 0,
to: 1,
},
{
property: "transform",
from: [
{
translateX: 200,
},
{
rotate: 90,
},
],
to: [
{
translateX: "0",
},
{
rotate: 0,
},
],
},
],
};
return command;
}
}
In case of using Execute Command Directive with Jsx For Apl, token
property must be provided to APL component: <APL token="token_name">
.
// JumpIntentHandler.tsx
import * as React from "react";
import { HandlerInput, RequestHandler } from "ask-sdk";
import { Command } from "ask-sdk-jsx-for-apl";
import { interfaces } from "ask-sdk-model";
export class JumpIntentHandler implements RequestHandler {
canHandle(handlerInput: HandlerInput): boolean | Promise<boolean> {
//...
}
handle(handlerInput: HandlerInput) {
const responseBuilder = handlerInput.responseBuilder;
responseBuilder.addDirective({
type: "Alexa.Presentation.APL.ExecuteCommands",
token: "animalAplToken",
commands: [
this.getJumpCommand() as interfaces.alexa.presentation.apl.SequentialCommand,
],
});
return responseBuilder.getResponse();
}
getJumpCommand(): Command {
const jumpCommand: Command = {
type: "Sequential",
commands: [
this.getMoveAnimation(0, -200, "animalImage"),
this.getMoveAnimation(-200, 0, "animalImage"),
],
};
return jumpCommand;
}
getMoveAnimation(fromY: number, toY: number, componentId: string): Command {
const moveAnimation: Command = {
type: "AnimateItem",
duration: 500,
value: [
{
property: "transform",
from: [
{
translateY: fromY,
},
],
to: [
{
translateY: toY,
},
],
},
],
componentId: componentId,
};
return moveAnimation;
}
}
// AnimalApl.tsx
//...
export class AnimalApl extends React.Component<{ animal: Animal }> {
public render() {
return (
<APL token="animalAplToken">
<MainTemplate>
<Frame width="100vw" height="100vh" backgroundColor="rgb(22,147,165)">
<Container
width="100vw"
height="100vh"
alignItems="center"
justifyContent="spaceAround"
>
<Text text={this.props.animal.title} fontSize="50px"
color="rgb(251,184,41)"
/>
<Image
id="animalImage"
source={this.props.animal.image}
height="60vh"
width="30vh"
scale="best-fit"
/>
</Container>
</Frame>
</MainTemplate>
</APL>
);
}
}
In case of using User-defined Commands with Jsx For Apl, commands
property must be provided to APL component: <APL commands={commands_map}>
Currently parent-child component relationship for Responsive Templates(AlexaImageList, AlexaLists, AlexaPaginatedList, AlexaTextList) is not supported by Jsx for APL yet.
The solution of providing items to these Responsive Templates can be implemented via populating their listItems
property.
// MyImageList.jsx
import { APL, MainTemplate } from "ask-sdk-jsx-for-apl";
import { AlexaImageList } from "ask-sdk-jsx-for-apl/alexa-layouts";
const imageList = [
{
primaryText: "First list item",
secondaryText: "Secondary text",
imageSource: "https://d2o906d8ln7ui1.cloudfront.net/images/md_gruyere.png"
}
];
export class MyImageList extends React.Component {
render() {
return (
<APL>
<MainTemplate>
<AlexaImageList listItems={imageList} imageBlurredBackground={true} />
</MainTemplate>
</APL>
);
}
}
Jsx For Apl has one to one property mapping with APL Document Properties inside APL
component. You can check some of the example use cases below.
Skill developers may need to use Resources and/or Styles rather than binding data to a component on runtime utilizing React Props or React Context.
In that case resources
and/or styles
must be provided to APL
component.
// MyStylesAndResourcesApl.jsx
...
const resources = [
{
colors: {
"MyBlue": "#0022f3"
}
}
];
const styles = {
textJsxStyle: {
values: [
{
fontSize: 24,
color: "@MyBlue"
}
]
}
}
export class MyStylesAndResourcesApl extends React.Component {
render() {
return (
<APL resources={resources} styles={styles}>
<MainTemplate>
<Text style="textJsxStyle" text="Testing Jsx Styles" />
</MainTemplate>
</APL>
);
}
}
Skill developers may need to use APL Data Sources and use them via APL Data-Binding rather than binding data to a component on runtime utilizing React Props or React Context.
When there is a need of using APL Data Source, data source object must be provided to dataSources
property of APL
component.
// FruitApl.jsx
...
export class FruitApl extends React.Component {
render() {
const fruitData = {
apple: {
title: "apple",
image: "https://m.media-amazon.com/images/G/01/voicehub/vesper_fruit_skill/licensed_images/Apple.jpg"
}
};
return (
<APL dataSources={fruitData}>
<MainTemplate parameters={["payload"]}>
<Frame width="100vw" height="100vh" backgroundColor="rgb(22,147,165)">
<Container width="100vw" height="100vh" alignItems="center" justifyContent="spaceAround">
<Text text="${payload.apple.title}" fontSize="50px" color="rgb(251,184,41)" />
<Image source="${payload.apple.image}" height="60vh" width="30vh" scale="best-fit" />
</Container>
</Frame>
</MainTemplate>
</APL>
);
}
}
The defined React components inside a skill can be used multiple times to serve different content. They basically serve like APL Layout.
There can be times when skill developers want to reduce directive payload size and using APL Layout can be a solution for this situation.
// MySkillApl.jsx
import * as React from "react";
import omit from 'lodash/omit';
import { APL, MainTemplate, APLComponent } from "ask-sdk-jsx-for-apl";
//Define layouts json to push into APL.
const layouts = {
MyLayout: {
parameters: [
"parameterText"
],
item: [
{
type: "Text",
text: "${parameterText}",
width: "100%"
}
]
}
}
//Create React Components for the defined layouts.
const MyLayout = (props) => {
return (
<>
<APLComponent definition={{ ...omit(props, ['children']), type: 'MyLayout' }}>
{props.children}
</APLComponent>
</>
);
}
//Use Defined Layout React Component inside APL.
export class MySkillApl extends React.Component {
render() {
return (
<APL layouts={layouts}>
<MainTemplate>
<MyLayout parameterText="Testing Jsx Layouts" />
</MainTemplate>
</APL>
);
}
}
If you are coding with typescript, you can even leverage IDE auto-completion ability by defining props for your Layout component.
// MyLayout.tsx
...
export interface MyLayoutProps {
parameterText?: string;
}
//Create React Components for the defined layouts.
export MyLayout = (props: React.PropsWithChildren<MyLayoutProps>) => {
return (
<>
<APLComponent definition={{ ...omit(props, ['children']), type: 'MyLayout' }}>
{props.children}
</APLComponent>
</>
);
}
To use VectorGraphic component with JSX for APL, graphics
property must be provided inside APL
component following Vector Graphic Format guideline.
// MyGraphicsApl.jsx
import * as React from "react";
import { APL, MainTemplate, VectorGraphic } from "ask-sdk-jsx-for-apl";
const graphics = {
parameterizedCircle: {
type: "AVG",
version: "1.0",
height: 100,
width: 100,
parameters: [
{
name: "circleColor",
type: "color",
default: "black"
},
{
name: "circleBorderWidth",
type: "number",
default: 2
}
],
items: [
{
type: "path",
pathData: "M25,50 a25,25 0 1 1 50,0 a25,25 0 1 1 -50,0",
stroke: "${circleColor}",
strokeWidth: "${circleBorderWidth}",
fill: "none"
}
]
}
}
export class MyGraphicsApl extends React.Component {
render() {
return (
<APL graphics={graphics}>
<MainTemplate>
<VectorGraphic source="parameterizedCircle" width={100} height={100}
circleColor="red" circleBorderWidth={15} />
</MainTemplate>
</APL>
);
}
}