Merge branch 'release' of https://github.com/appsmithorg/appsmith into release
This commit is contained in:
commit
902fd2dcc7
3
app/client/src/assets/icons/widget/video.svg
Normal file
3
app/client/src/assets/icons/widget/video.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="17" height="14" viewBox="0 0 17 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.8682 7.35302L6.52617 9.1177V5.23541L10.8682 7.35302ZM14.4211 2.41192H2.57929L2.57891 11.5883H14.4211V2.41192ZM2.97404 1.00016C1.78945 0.987885 0.999229 1.68148 1 2.75257V11.2353C0.999615 12.2941 1.78945 13 2.97363 13H14.0264C15.2105 13 16 12.2579 16 11.2353L15.9996 2.76485C15.9996 1.70604 15.2102 1.00016 14.026 1.00016H2.97404Z" fill="#C4C4C4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 504 B |
|
|
@ -0,0 +1,64 @@
|
|||
import React from "react";
|
||||
import {
|
||||
Popover,
|
||||
PopoverInteractionKind,
|
||||
PopoverPosition,
|
||||
} from "@blueprintjs/core";
|
||||
import { Colors } from "constants/Colors";
|
||||
import VideoComponent, { VideoComponentProps } from "./VideoComponent";
|
||||
import styled, { AnyStyledComponent } from "styled-components";
|
||||
import { ControlIcons } from "icons/ControlIcons";
|
||||
const PlayIcon = styled(ControlIcons.PLAY_VIDEO as AnyStyledComponent)`
|
||||
position: relative;
|
||||
top: 10px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
svg {
|
||||
path {
|
||||
fill: ${Colors.POMEGRANATE};
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const PlayerWrapper = styled.div` import React, { Ref } from "react";
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
`;
|
||||
|
||||
const PopoverVideo = (props: VideoComponentProps) => {
|
||||
return (
|
||||
<div onClick={e => e.stopPropagation()}>
|
||||
<Popover
|
||||
position={PopoverPosition.AUTO}
|
||||
interactionKind={PopoverInteractionKind.CLICK}
|
||||
minimal
|
||||
usePortal
|
||||
enforceFocus={false}
|
||||
lazy={true}
|
||||
modifiers={{
|
||||
flip: {
|
||||
behavior: ["right", "left", "bottom", "top"],
|
||||
},
|
||||
keepTogether: {
|
||||
enabled: false,
|
||||
},
|
||||
arrow: {
|
||||
enabled: false,
|
||||
},
|
||||
preventOverflow: {
|
||||
enabled: true,
|
||||
boundariesElement: "viewport",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<PlayIcon></PlayIcon>
|
||||
<PlayerWrapper>
|
||||
<VideoComponent url={props.url} />
|
||||
</PlayerWrapper>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PopoverVideo;
|
||||
|
|
@ -15,7 +15,7 @@ import {
|
|||
Condition,
|
||||
} from "widgets/TableWidget";
|
||||
import { isString } from "lodash";
|
||||
import VideoComponent from "components/designSystems/appsmith/VideoComponent";
|
||||
import PopoverVideo from "components/designSystems/appsmith/PopoverVideo";
|
||||
import Button from "components/editorComponents/Button";
|
||||
import AutoToolTipComponent from "components/designSystems/appsmith/AutoToolTipComponent";
|
||||
import TableColumnMenuPopup from "./TableColumnMenu";
|
||||
|
|
@ -505,7 +505,7 @@ export const renderCell = (
|
|||
} else if (isString(value) && youtubeRegex.test(value)) {
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden} className="video-cell">
|
||||
<VideoComponent url={value} />
|
||||
<PopoverVideo url={value} />
|
||||
</CellWrapper>
|
||||
);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,73 +1,72 @@
|
|||
import React from "react";
|
||||
import ReactPlayer from "react-player";
|
||||
import {
|
||||
Popover,
|
||||
PopoverInteractionKind,
|
||||
PopoverPosition,
|
||||
} from "@blueprintjs/core";
|
||||
import { ControlIcons } from "icons/ControlIcons";
|
||||
import styled, { AnyStyledComponent } from "styled-components";
|
||||
import { Colors } from "constants/Colors";
|
||||
|
||||
const PlayerWrapper = styled.div`
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
`;
|
||||
|
||||
const PlayIcon = styled(ControlIcons.PLAY_VIDEO as AnyStyledComponent)`
|
||||
position: relative;
|
||||
top: 10px;
|
||||
&:hover {
|
||||
svg {
|
||||
path {
|
||||
fill: ${Colors.POMEGRANATE};
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface VideoComponentProps {
|
||||
url: string;
|
||||
import React, { Ref } from "react";
|
||||
import styled from "styled-components";
|
||||
import { ENTER_VIDEO_URL } from "constants/messages";
|
||||
export interface VideoComponentProps {
|
||||
url?: string;
|
||||
autoplay?: boolean;
|
||||
controls?: boolean;
|
||||
onStart?: () => void;
|
||||
onPlay?: () => void;
|
||||
onPause?: () => void;
|
||||
onEnded?: () => void;
|
||||
onReady?: () => void;
|
||||
onProgress?: () => void;
|
||||
onSeek?: () => void;
|
||||
onError?: () => void;
|
||||
player?: Ref<ReactPlayer>;
|
||||
}
|
||||
|
||||
const VideoComponent = (props: VideoComponentProps) => {
|
||||
return (
|
||||
<div onClick={e => e.stopPropagation()}>
|
||||
<Popover
|
||||
position={PopoverPosition.AUTO}
|
||||
interactionKind={PopoverInteractionKind.CLICK}
|
||||
minimal
|
||||
usePortal
|
||||
enforceFocus={false}
|
||||
lazy={true}
|
||||
modifiers={{
|
||||
flip: {
|
||||
behavior: ["right", "left", "bottom", "top"],
|
||||
},
|
||||
keepTogether: {
|
||||
enabled: false,
|
||||
},
|
||||
arrow: {
|
||||
enabled: false,
|
||||
},
|
||||
preventOverflow: {
|
||||
enabled: true,
|
||||
boundariesElement: "viewport",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<PlayIcon width="80" height="52" color="black" />
|
||||
<PlayerWrapper>
|
||||
<ReactPlayer
|
||||
playing={true}
|
||||
url={props.url}
|
||||
width="100%"
|
||||
height="100%"
|
||||
/>
|
||||
</PlayerWrapper>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const ErrorContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export default VideoComponent;
|
||||
const Error = styled.span``;
|
||||
|
||||
export default function VideoComponent(props: VideoComponentProps) {
|
||||
const {
|
||||
url,
|
||||
autoplay,
|
||||
controls,
|
||||
onStart,
|
||||
onPlay,
|
||||
onPause,
|
||||
onEnded,
|
||||
onReady,
|
||||
onProgress,
|
||||
onSeek,
|
||||
onError,
|
||||
player,
|
||||
} = props;
|
||||
return (
|
||||
<>
|
||||
{url ? (
|
||||
<ReactPlayer
|
||||
url={url}
|
||||
ref={player}
|
||||
playing={autoplay}
|
||||
controls={controls || true}
|
||||
onStart={onStart}
|
||||
onPlay={onPlay}
|
||||
onPause={onPause}
|
||||
onEnded={onEnded}
|
||||
onReady={onReady}
|
||||
onProgress={onProgress}
|
||||
onSeek={onSeek}
|
||||
onError={onError}
|
||||
width="100%"
|
||||
height="100%"
|
||||
pip={false}
|
||||
/>
|
||||
) : (
|
||||
<ErrorContainer>
|
||||
<Error>{ENTER_VIDEO_URL}</Error>
|
||||
</ErrorContainer>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ export enum EventType {
|
|||
ON_MARKER_CLICK = "ON_MARKER_CLICK",
|
||||
ON_CREATE_MARKER = "ON_CREATE_MARKER",
|
||||
ON_TAB_CHANGE = "ON_TAB_CHANGE",
|
||||
ON_VIDEO_START = "ON_VIDEO_START",
|
||||
ON_VIDEO_END = "ON_VIDEO_END",
|
||||
ON_VIDEO_PLAY = "ON_VIDEO_PLAY",
|
||||
ON_VIDEO_PAUSE = "ON_VIDEO_PAUSE",
|
||||
}
|
||||
|
||||
export type ActionType =
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ const FIELD_VALUES: Record<
|
|||
// onRowSelected: "Function Call",
|
||||
// onPageChange: "Function Call",
|
||||
},
|
||||
VIDEO_WIDGET: {
|
||||
url: "string",
|
||||
autoPlay: "boolean",
|
||||
isVisible: "boolean",
|
||||
},
|
||||
IMAGE_WIDGET: {
|
||||
image: "string",
|
||||
defaultImage: "string",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ export const HelpMap = {
|
|||
path: "/widget-reference/table",
|
||||
searchKey: "Table",
|
||||
},
|
||||
VIDEO_WIDGET: {
|
||||
path: "/widget-reference/video",
|
||||
searchKey: "Video",
|
||||
},
|
||||
DROP_DOWN_WIDGET: {
|
||||
path: "/widget-reference/dropdown",
|
||||
searchKey: "Dropdown",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ export enum WidgetTypes {
|
|||
CANVAS_WIDGET = "CANVAS_WIDGET",
|
||||
ICON_WIDGET = "ICON_WIDGET",
|
||||
FILE_PICKER_WIDGET = "FILE_PICKER_WIDGET",
|
||||
VIDEO_WIDGET = "VIDEO_WIDGET",
|
||||
}
|
||||
|
||||
export type WidgetType = keyof typeof WidgetTypes;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ export const NAME_SPACE_ERROR = "Name must not have spaces";
|
|||
export const FORM_VALIDATION_EMPTY_EMAIL = "Please enter an email";
|
||||
export const FORM_VALIDATION_INVALID_EMAIL =
|
||||
"Please provide a valid email address";
|
||||
export const ENTER_VIDEO_URL = "Please provide a valid url";
|
||||
|
||||
export const FORM_VALIDATION_EMPTY_PASSWORD = "Please enter the password";
|
||||
export const FORM_VALIDATION_PASSWORD_RULE =
|
||||
"Please provide a password with a minimum of 6 characters";
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { ReactComponent as CollapseIcon } from "assets/icons/widget/collapse.svg
|
|||
import { ReactComponent as ContainerIcon } from "assets/icons/widget/container.svg";
|
||||
import { ReactComponent as DatePickerIcon } from "assets/icons/widget/datepicker.svg";
|
||||
import { ReactComponent as TableIcon } from "assets/icons/widget/table.svg";
|
||||
import { ReactComponent as VideoIcon } from "assets/icons/widget/video.svg";
|
||||
import { ReactComponent as DropDownIcon } from "assets/icons/widget/dropdown.svg";
|
||||
import { ReactComponent as CheckboxIcon } from "assets/icons/widget/checkbox.svg";
|
||||
import { ReactComponent as RadioGroupIcon } from "assets/icons/widget/radio.svg";
|
||||
|
|
@ -60,6 +61,11 @@ export const WidgetIcons: {
|
|||
<TableIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
VIDEO_WIDGET: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<VideoIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
DROP_DOWN_WIDGET: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<DropDownIcon />
|
||||
|
|
|
|||
|
|
@ -119,6 +119,76 @@ const PropertyPaneConfigResponse: PropertyPaneConfigsResponse["data"] = {
|
|||
],
|
||||
},
|
||||
],
|
||||
VIDEO_WIDGET: [
|
||||
{
|
||||
id: "17.1",
|
||||
sectionName: "General",
|
||||
children: [
|
||||
{
|
||||
id: "17.1.1",
|
||||
propertyName: "url",
|
||||
label: "Url",
|
||||
controlType: "INPUT_TEXT",
|
||||
placeholderText: "Enter url",
|
||||
inputType: "TEXT",
|
||||
},
|
||||
{
|
||||
id: "17.1.1",
|
||||
propertyName: "autoPlay",
|
||||
label: "autoPlay",
|
||||
helpText: "Video will be automatically played",
|
||||
controlType: "SWITCH",
|
||||
isJSConvertible: true,
|
||||
},
|
||||
{
|
||||
id: "17.1.2",
|
||||
helpText: "Controls the visibility of the widget",
|
||||
propertyName: "isVisible",
|
||||
label: "Visible",
|
||||
controlType: "SWITCH",
|
||||
isJSConvertible: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "17.2",
|
||||
sectionName: "Actions",
|
||||
children: [
|
||||
{
|
||||
id: "17.2.1",
|
||||
helpText: "Triggers an action when the video starts playing",
|
||||
propertyName: "onStart",
|
||||
label: "onStart",
|
||||
controlType: "ACTION_SELECTOR",
|
||||
isJSConvertible: true,
|
||||
},
|
||||
{
|
||||
id: "17.2.2",
|
||||
helpText: "Triggers an action when the video ends",
|
||||
propertyName: "onEnd",
|
||||
label: "onEnd",
|
||||
controlType: "ACTION_SELECTOR",
|
||||
isJSConvertible: true,
|
||||
},
|
||||
{
|
||||
id: "17.2.3",
|
||||
helpText: "Triggers an action when the video is played",
|
||||
propertyName: "onPlay",
|
||||
label: "onPlay",
|
||||
controlType: "ACTION_SELECTOR",
|
||||
isJSConvertible: true,
|
||||
},
|
||||
{
|
||||
id: "17.2.4",
|
||||
helpText: "Triggers an action when the video is paused",
|
||||
propertyName: "onPause",
|
||||
label: "onPause",
|
||||
controlType: "ACTION_SELECTOR",
|
||||
isJSConvertible: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
TABLE_WIDGET: [
|
||||
{
|
||||
id: "7.1",
|
||||
|
|
|
|||
|
|
@ -92,6 +92,14 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
widgetName: "DatePicker",
|
||||
defaultDate: moment().format("DD/MM/YYYY HH:mm"),
|
||||
},
|
||||
|
||||
VIDEO_WIDGET: {
|
||||
rows: 7,
|
||||
columns: 7,
|
||||
widgetName: "Video",
|
||||
url: "https://www.youtube.com/watch?v=mzqK0QIZRLs",
|
||||
autoPlay: false,
|
||||
},
|
||||
TABLE_WIDGET: {
|
||||
rows: 7,
|
||||
columns: 8,
|
||||
|
|
|
|||
|
|
@ -74,6 +74,11 @@ const WidgetSidebarResponse: {
|
|||
widgetCardName: "Table",
|
||||
key: generateReactKey(),
|
||||
},
|
||||
{
|
||||
type: "VIDEO_WIDGET",
|
||||
widgetCardName: "Video",
|
||||
key: generateReactKey(),
|
||||
},
|
||||
{
|
||||
type: "MAP_WIDGET",
|
||||
widgetCardName: "Map",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { FormButtonWidgetProps } from "widgets/FormButtonWidget";
|
|||
import { MapWidgetProps } from "widgets/MapWidget";
|
||||
import { ModalWidgetProps } from "widgets/ModalWidget";
|
||||
import { IconWidgetProps } from "widgets/IconWidget";
|
||||
import { VideoWidgetProps } from "widgets/VideoWidget";
|
||||
|
||||
const initialState: WidgetConfigReducerState = WidgetConfigResponse;
|
||||
|
||||
|
|
@ -57,6 +58,7 @@ export interface WidgetConfigReducerState {
|
|||
WidgetConfigProps;
|
||||
DATE_PICKER_WIDGET: Partial<DatePickerWidgetProps> & WidgetConfigProps;
|
||||
TABLE_WIDGET: Partial<TableWidgetProps> & WidgetConfigProps;
|
||||
VIDEO_WIDGET: Partial<VideoWidgetProps> & WidgetConfigProps;
|
||||
DROP_DOWN_WIDGET: Partial<DropdownWidgetProps> & WidgetConfigProps;
|
||||
CHECKBOX_WIDGET: Partial<CheckboxWidgetProps> & WidgetConfigProps;
|
||||
RADIO_GROUP_WIDGET: Partial<RadioGroupWidgetProps> & WidgetConfigProps;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ import TableWidget, {
|
|||
TableWidgetProps,
|
||||
ProfiledTableWidget,
|
||||
} from "widgets/TableWidget";
|
||||
import VideoWidget, {
|
||||
VideoWidgetProps,
|
||||
ProfiledVideoWidget,
|
||||
} from "widgets/VideoWidget";
|
||||
import TabsWidget, {
|
||||
TabsWidgetProps,
|
||||
TabContainerWidgetProps,
|
||||
|
|
@ -204,6 +208,21 @@ export default class WidgetBuilderRegistry {
|
|||
TableWidget.getDefaultPropertiesMap(),
|
||||
TableWidget.getMetaPropertiesMap(),
|
||||
);
|
||||
|
||||
WidgetFactory.registerWidgetBuilder(
|
||||
"VIDEO_WIDGET",
|
||||
{
|
||||
buildWidget(widgetData: VideoWidgetProps): JSX.Element {
|
||||
return <ProfiledVideoWidget {...widgetData} />;
|
||||
},
|
||||
},
|
||||
VideoWidget.getPropertyValidationMap(),
|
||||
VideoWidget.getDerivedPropertiesMap(),
|
||||
VideoWidget.getTriggerPropertyMap(),
|
||||
VideoWidget.getDefaultPropertiesMap(),
|
||||
VideoWidget.getMetaPropertiesMap(),
|
||||
);
|
||||
|
||||
WidgetFactory.registerWidgetBuilder(
|
||||
"FILE_PICKER_WIDGET",
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,6 +67,13 @@ export const entityDefinitions = {
|
|||
isVisible: isVisible,
|
||||
searchText: "string",
|
||||
}),
|
||||
VIDEO_WIDGET: (widget: any) => ({
|
||||
"!doc":
|
||||
"Video widget can be used for playing a variety of URLs, including file paths, YouTube, Facebook, Twitch, SoundCloud, Streamable, Vimeo, Wistia, Mixcloud, and DailyMotion.",
|
||||
"!url": "https://docs.appsmith.com/widget-reference/video",
|
||||
playState: "number",
|
||||
autoPlay: "bool",
|
||||
}),
|
||||
DROP_DOWN_WIDGET: {
|
||||
"!doc":
|
||||
"Dropdown is used to capture user input/s from a specified list of permitted inputs. A Dropdown can capture a single choice as well as multiple choices",
|
||||
|
|
|
|||
135
app/client/src/widgets/VideoWidget.tsx
Normal file
135
app/client/src/widgets/VideoWidget.tsx
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
import React, { Suspense, lazy } from "react";
|
||||
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||
import { WidgetType } from "constants/WidgetConstants";
|
||||
import { EventType } from "constants/ActionConstants";
|
||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||
import {
|
||||
WidgetPropertyValidationType,
|
||||
BASE_WIDGET_VALIDATION,
|
||||
} from "utils/ValidationFactory";
|
||||
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
||||
import Skeleton from "components/utils/Skeleton";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { retryPromise } from "utils/AppsmithUtils";
|
||||
import ReactPlayer from "react-player";
|
||||
|
||||
const VideoComponent = lazy(() =>
|
||||
retryPromise(() =>
|
||||
import("components/designSystems/appsmith/VideoComponent"),
|
||||
),
|
||||
);
|
||||
|
||||
export enum PlayState {
|
||||
NOT_STARTED = "NOT_STARTED",
|
||||
PAUSED = "PAUSED",
|
||||
ENDED = "ENDED",
|
||||
PLAYING = "PLAYING",
|
||||
}
|
||||
|
||||
class VideoWidget extends BaseWidget<VideoWidgetProps, WidgetState> {
|
||||
private _player = React.createRef<ReactPlayer>();
|
||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||
return {
|
||||
...BASE_WIDGET_VALIDATION,
|
||||
url: VALIDATION_TYPES.TEXT,
|
||||
};
|
||||
}
|
||||
|
||||
static getMetaPropertiesMap(): Record<string, any> {
|
||||
return {
|
||||
playState: PlayState.NOT_STARTED,
|
||||
};
|
||||
}
|
||||
|
||||
static getDefaultPropertiesMap(): Record<string, string> {
|
||||
return {};
|
||||
}
|
||||
|
||||
static getTriggerPropertyMap(): TriggerPropertiesMap {
|
||||
return {
|
||||
onStart: true,
|
||||
onEnd: true,
|
||||
onPlay: true,
|
||||
onPause: true,
|
||||
};
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: VideoWidgetProps) {
|
||||
return nextProps.url !== this.props.url;
|
||||
}
|
||||
|
||||
getPageView() {
|
||||
const { url, autoPlay, onStart, onEnd, onPause, onPlay } = this.props;
|
||||
return (
|
||||
<Suspense fallback={<Skeleton />}>
|
||||
<VideoComponent
|
||||
player={this._player}
|
||||
url={url}
|
||||
autoplay={autoPlay}
|
||||
controls={true}
|
||||
onStart={() => {
|
||||
this.updateWidgetMetaProperty("playState", PlayState.PLAYING);
|
||||
if (onStart) {
|
||||
super.executeAction({
|
||||
dynamicString: onStart,
|
||||
event: {
|
||||
type: EventType.ON_VIDEO_START,
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
onPlay={() => {
|
||||
this.updateWidgetMetaProperty("playState", PlayState.PLAYING);
|
||||
if (onPlay) {
|
||||
super.executeAction({
|
||||
dynamicString: onPlay,
|
||||
event: {
|
||||
type: EventType.ON_VIDEO_PLAY,
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
onPause={() => {
|
||||
//TODO: We do not want the pause event for onSeek or onEnd.
|
||||
this.updateWidgetMetaProperty("playState", PlayState.PAUSED);
|
||||
if (onPause) {
|
||||
super.executeAction({
|
||||
dynamicString: onPause,
|
||||
event: {
|
||||
type: EventType.ON_VIDEO_PAUSE,
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
onEnded={() => {
|
||||
this.updateWidgetMetaProperty("playState", PlayState.ENDED);
|
||||
if (onEnd) {
|
||||
super.executeAction({
|
||||
dynamicString: onEnd,
|
||||
event: {
|
||||
type: EventType.ON_VIDEO_END,
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
getWidgetType(): WidgetType {
|
||||
return "VIDEO_WIDGET";
|
||||
}
|
||||
}
|
||||
|
||||
export interface VideoWidgetProps extends WidgetProps {
|
||||
url: string;
|
||||
autoPlay: boolean;
|
||||
onStart?: string;
|
||||
onPause?: string;
|
||||
onPlay?: string;
|
||||
onEnd?: string;
|
||||
}
|
||||
|
||||
export default VideoWidget;
|
||||
export const ProfiledVideoWidget = Sentry.withProfiler(VideoWidget);
|
||||
Loading…
Reference in New Issue
Block a user