@playkit-js/transcript 3.0.1 → 3.0.2-canary.1-f9e6d51

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playkit-js/transcript",
3
- "version": "3.0.1",
3
+ "version": "3.0.2-canary.1-f9e6d51",
4
4
  "main": "dist/playkit-transcript.js",
5
5
  "license": "AGPL-3.0",
6
6
  "private": false,
@@ -75,7 +75,7 @@
75
75
  "html5 player"
76
76
  ],
77
77
  "dependencies": {
78
- "@playkit-js/common": "^1.0.2",
78
+ "@playkit-js/common": "^1.0.7",
79
79
  "stream-browserify": "^3.0.0"
80
80
  },
81
81
  "kaltura": {
@@ -1,10 +1,8 @@
1
- import * as styles from './caption.scss';
1
+ import {Component, h} from 'preact';
2
+ import {A11yWrapper, OnClickEvent} from '@playkit-js/common';
2
3
  import {secontsToTime} from '../../utils';
3
4
  import {CuePointData} from '../../types';
4
-
5
- const {ENTER, Space} = KalturaPlayer.ui.utils.KeyMap;
6
-
7
- import {Component, h} from 'preact';
5
+ import * as styles from './caption.scss';
8
6
 
9
7
  export interface CaptionProps {
10
8
  showTime: boolean;
@@ -57,12 +55,10 @@ export class Caption extends Component<ExtendedCaptionProps> {
57
55
  return false;
58
56
  }
59
57
 
60
- private _handleKeyPress = (event: KeyboardEvent) => {
61
- const keyCode = event.which || event.keyCode;
62
- if (keyCode === ENTER || keyCode === Space) {
58
+ private _handleKeyDown = (event: OnClickEvent, byKeyboard?: boolean) => {
59
+ if (byKeyboard) {
63
60
  event.preventDefault();
64
61
  this._gotoCurrentTime();
65
- return;
66
62
  }
67
63
  };
68
64
 
@@ -117,23 +113,23 @@ export class Caption extends Component<ExtendedCaptionProps> {
117
113
  const isHighlighted = Object.keys(highlighted)[0] === id;
118
114
 
119
115
  return (
120
- <div
121
- className={styles.caption}
122
- tabIndex={1}
123
- ref={node => {
124
- this._hotspotRef = node;
125
- }}
126
- onKeyDown={this._handleKeyPress}
127
- >
128
- {showTime && <div className={styles.captionTime}>{secontsToTime(startTime, longerThanHour)}</div>}
116
+ <A11yWrapper onClick={this._handleKeyDown}>
129
117
  <div
130
- onClick={this._handleClick}
131
- className={`${styles.captionContent} ${isHighlighted ? styles.highlighted : ''} ${showTime ? '' : styles.withoutTime}`}
132
- role="button"
133
- >
134
- {this._renderText(caption.text)}
118
+ className={styles.caption}
119
+ tabIndex={1}
120
+ area-label={caption.text}
121
+ ref={node => {
122
+ this._hotspotRef = node;
123
+ }}
124
+ role="listitem">
125
+ {showTime && <div className={styles.captionTime}>{secontsToTime(startTime, longerThanHour)}</div>}
126
+ <div
127
+ onClick={this._handleClick}
128
+ className={`${styles.captionContent} ${isHighlighted ? styles.highlighted : ''} ${showTime ? '' : styles.withoutTime}`}>
129
+ {this._renderText(caption.text)}
130
+ </div>
135
131
  </div>
136
- </div>
132
+ </A11yWrapper>
137
133
  );
138
134
  }
139
135
  }
@@ -4,7 +4,7 @@ import {Caption} from '../caption';
4
4
  import * as styles from './captionList.scss';
5
5
  import {HighlightedMap, CuePointData} from '../../types';
6
6
 
7
- const {End, Home} = KalturaPlayer.ui.utils.KeyMap;
7
+ const {END, HOME} = KalturaPlayer.ui.utils.KeyMap;
8
8
 
9
9
  export interface CaptionProps {
10
10
  showTime: boolean;
@@ -95,9 +95,9 @@ export class CaptionList extends Component<Props> {
95
95
  };
96
96
 
97
97
  private _handleKeyUp = (event: KeyboardEvent) => {
98
- if (event.keyCode === End) {
98
+ if (event.keyCode === END) {
99
99
  this._lastCaptionRef?._hotspotRef?.focus();
100
- } else if (event.keyCode === Home) {
100
+ } else if (event.keyCode === HOME) {
101
101
  this._firstCaptionRef?._hotspotRef?.focus();
102
102
  }
103
103
  };
@@ -105,7 +105,7 @@ export class CaptionList extends Component<Props> {
105
105
  render() {
106
106
  const {data} = this.props;
107
107
  return (
108
- <div className={styles.transcriptWrapper} onKeyUp={this._handleKeyUp}>
108
+ <div className={styles.transcriptWrapper} onKeyUp={this._handleKeyUp} role="list">
109
109
  {data.map((captionData, index) => {
110
110
  const captionProps = this._getCaptionProps(captionData);
111
111
  return (
@@ -116,7 +116,7 @@ export class CaptionList extends Component<Props> {
116
116
  } else if (index === data.length - 1) {
117
117
  this._lastCaptionRef = node;
118
118
  }
119
- if (captionProps.highlighted) {
119
+ if (captionProps.highlighted[captionData.id]) {
120
120
  this._currentCaptionRef = node;
121
121
  }
122
122
  }}
@@ -3,14 +3,20 @@ import * as styles from './close-button.scss';
3
3
  import {A11yWrapper} from '@playkit-js/common';
4
4
  import {icons} from '../icons';
5
5
  const {Icon} = KalturaPlayer.ui.components;
6
+ const {withText, Text} = KalturaPlayer.ui.preacti18n;
7
+
8
+ const translates = {
9
+ closeLabel: <Text id="transcript.hide_plugin">Hide Transcript</Text>
10
+ };
6
11
 
7
12
  interface CloseButtonProps {
8
13
  onClick: () => void;
14
+ closeLabel?: string;
9
15
  }
10
16
 
11
- export const CloseButton = (props: CloseButtonProps) => (
17
+ export const CloseButton = withText(translates)((props: CloseButtonProps) => (
12
18
  <A11yWrapper onClick={props.onClick}>
13
- <button className={styles.closeBtn} tabIndex={1}>
19
+ <button className={styles.closeBtn} tabIndex={1} aria-label={props.closeLabel}>
14
20
  <Icon
15
21
  id="transcript-plugin-close-button"
16
22
  height={icons.BigSize}
@@ -20,4 +26,4 @@ export const CloseButton = (props: CloseButtonProps) => (
20
26
  />
21
27
  </button>
22
28
  </A11yWrapper>
23
- );
29
+ ));
@@ -26,19 +26,3 @@
26
26
  background-size: cover;
27
27
  }
28
28
  }
29
- .popover-menu-item {
30
- display: flex;
31
- align-items: center;
32
- padding: 9px 24px 9px 16px;
33
- white-space: nowrap;
34
- min-height: 30px;
35
- line-height: 18px;
36
- font-size: 15px;
37
- &:hover {
38
- cursor: pointer;
39
- background-color: $semigray-color;
40
- }
41
- &:focus {
42
- outline: 1px solid $focus-color;
43
- }
44
- }
@@ -1,10 +1,11 @@
1
- import {h, Component, ComponentChild, VNode} from 'preact';
2
- import {Popover, PopoverHorizontalPositions, PopoverVerticalPositions} from '../../utils';
3
- import {PopoverMenu, PopoverMenuItem} from '../popover-menu';
1
+ import {h, Component, VNode} from 'preact';
2
+ import {A11yWrapper} from '@playkit-js/common';
3
+ import {Popover, PopoverMenuItem} from '../popover';
4
4
  import * as styles from './download-print-menu.scss';
5
5
  import {DownloadIcon, PrintIcon} from './download-print-icons';
6
6
 
7
- const {ENTER, Esc} = KalturaPlayer.ui.utils.KeyMap;
7
+ const {Tooltip} = KalturaPlayer.ui.components;
8
+ const {withText, Text} = KalturaPlayer.ui.preacti18n;
8
9
 
9
10
  export function downloadContent(content: string, name: string): void {
10
11
  const blob = new Blob([content], {type: 'text/plain;charset=utf-8;'});
@@ -29,7 +30,6 @@ export function downloadContent(content: string, name: string): void {
29
30
  anchor.click();
30
31
  anchor.remove();
31
32
  }
32
-
33
33
  export function printContent(content: string): void {
34
34
  const printWindow = window.open('', '', 'width=400,height=600');
35
35
  if (printWindow) {
@@ -42,9 +42,9 @@ export function printContent(content: string): void {
42
42
  }
43
43
 
44
44
  interface DownloadPrintMenuProps {
45
- dropdownAriaLabel: string;
46
- printButtonAriaLabel: string;
47
- downloadButtonAriaLabel: string;
45
+ printDownloadAreaLabel?: string;
46
+ printTranscript?: string;
47
+ downloadTranscript?: string;
48
48
  onDownload: () => void;
49
49
  onPrint: () => void;
50
50
  downloadDisabled: boolean;
@@ -52,113 +52,77 @@ interface DownloadPrintMenuProps {
52
52
  }
53
53
 
54
54
  interface ButtonProperties {
55
- ['aria-label']: string;
56
- buttonStyles: string;
57
- onClick?: () => void;
55
+ ['aria-label']?: string;
58
56
  tabIndex?: number;
59
- iconStyles: string;
60
57
  icon: VNode;
61
58
  }
62
59
 
63
- interface DownloadPrintMenuState {
64
- popoverOpen: boolean;
65
- }
66
-
67
- export class DownloadPrintMenu extends Component<DownloadPrintMenuProps, DownloadPrintMenuState> {
68
- state: DownloadPrintMenuState = {
69
- popoverOpen: false
70
- };
71
-
72
- private _onDownloadClicked = () => {
73
- this.props.onDownload();
74
- };
75
-
76
- private _onPrintClicked = () => {
77
- this.props.onPrint();
78
- };
79
- private _onKeyDown = (e: KeyboardEvent, callBack: Function) => {
80
- if (e.keyCode !== ENTER && e.keyCode !== Esc) {
81
- // don't stopPropagation on ESC and Enter pressed as it prevent the popup closing
82
- e.stopPropagation();
83
- }
84
- switch (e.keyCode) {
85
- case 13: // Enter pressed
86
- callBack();
87
- break;
88
- }
89
- };
90
- private _popoverMenuItemRenderer = (el: PopoverMenuItem) => (
91
- <div
92
- tabIndex={1}
93
- role="button"
94
- onClick={() => el.onMenuChosen()}
95
- onKeyDown={(e: KeyboardEvent) => this._onKeyDown(e, el.onMenuChosen)}
96
- className={styles.popoverMenuItem}>
97
- {el.label}
98
- </div>
99
- );
60
+ const translates = () => ({
61
+ printDownloadAreaLabel: <Text id="transcript.print_download_area_label">Download or print current transcript</Text>,
62
+ printTranscript: <Text id="transcript.print_transcript">Print current transcript</Text>,
63
+ downloadTranscript: <Text id="transcript.download_transcript">Download current transcript</Text>
64
+ });
100
65
 
101
- private _getPopoverMenuOptions = () => {
66
+ export class DownloadPrintMenuComponent extends Component<DownloadPrintMenuProps> {
67
+ private _getPopoverMenuOptions = (): Array<PopoverMenuItem> => {
102
68
  return [
103
69
  {
104
- label: this.props.downloadButtonAriaLabel,
105
- onMenuChosen: this._onDownloadClicked
70
+ label: this.props.downloadTranscript,
71
+ onMenuChosen: this.props.onDownload
106
72
  },
107
73
  {
108
- label: this.props.printButtonAriaLabel,
109
- onMenuChosen: this._onPrintClicked
74
+ label: this.props.printTranscript,
75
+ onMenuChosen: this.props.onPrint
110
76
  }
111
77
  ];
112
78
  };
113
79
 
114
- private _renderIcon = ({buttonStyles, tabIndex = 0, iconStyles, icon, ...props}: ButtonProperties): ComponentChild => {
80
+ private _renderIcon = ({tabIndex = 0, icon, ...props}: ButtonProperties): VNode => {
115
81
  return (
116
- <button className={buttonStyles} tabIndex={tabIndex} {...props}>
117
- <div className={iconStyles}>{icon}</div>
82
+ <button className={styles.downloadPrintButton} tabIndex={tabIndex} {...props}>
83
+ <div className={styles.icon}>{icon}</div>
118
84
  </button>
119
85
  );
120
86
  };
121
87
 
122
- private _popoverContent = () => {
123
- return <PopoverMenu itemRenderer={this._popoverMenuItemRenderer} options={this._getPopoverMenuOptions()} />;
124
- };
125
-
126
88
  render(props: DownloadPrintMenuProps) {
127
- const {downloadDisabled, printDisabled} = props;
89
+ const {downloadDisabled, printDisabled, printDownloadAreaLabel, printTranscript, downloadTranscript} = props;
128
90
  if (!downloadDisabled && !printDisabled) {
129
91
  return (
130
- <Popover
131
- className="download-print-popover"
132
- verticalPosition={PopoverVerticalPositions.Bottom}
133
- horizontalPosition={PopoverHorizontalPositions.Left}
134
- content={this._popoverContent()}>
92
+ <Popover label={printDownloadAreaLabel!} options={this._getPopoverMenuOptions()}>
135
93
  {this._renderIcon({
136
- ['aria-label']: props.dropdownAriaLabel,
137
- buttonStyles: styles.downloadPrintButton,
138
- iconStyles: styles.icon,
94
+ ['aria-label']: printDownloadAreaLabel,
139
95
  icon: <DownloadIcon />
140
96
  })}
141
97
  </Popover>
142
98
  );
143
99
  }
144
100
  if (!downloadDisabled && printDisabled) {
145
- return this._renderIcon({
146
- ['aria-label']: props.downloadButtonAriaLabel,
147
- buttonStyles: styles.downloadPrintButton,
148
- iconStyles: styles.icon,
149
- onClick: this._onDownloadClicked,
150
- icon: <DownloadIcon />
151
- });
101
+ return (
102
+ <Tooltip label={downloadTranscript} type="bottom">
103
+ <A11yWrapper onClick={this.props.onDownload}>
104
+ {this._renderIcon({
105
+ ['aria-label']: downloadTranscript,
106
+ icon: <DownloadIcon />
107
+ })}
108
+ </A11yWrapper>
109
+ </Tooltip>
110
+ );
152
111
  }
153
112
  if (downloadDisabled && !printDisabled) {
154
- return this._renderIcon({
155
- ['aria-label']: props.printButtonAriaLabel,
156
- buttonStyles: styles.downloadPrintButton,
157
- iconStyles: styles.icon,
158
- onClick: this._onPrintClicked,
159
- icon: <PrintIcon />
160
- });
113
+ return (
114
+ <Tooltip label={printTranscript} type="bottom">
115
+ <A11yWrapper onClick={this.props.onPrint}>
116
+ {this._renderIcon({
117
+ ['aria-label']: printTranscript,
118
+ icon: <PrintIcon />
119
+ })}
120
+ </A11yWrapper>
121
+ </Tooltip>
122
+ );
161
123
  }
162
124
  return null;
163
125
  }
164
126
  }
127
+
128
+ export const DownloadPrintMenu = withText(translates)(DownloadPrintMenuComponent);
@@ -2,7 +2,15 @@ import {h} from 'preact';
2
2
  import * as styles from './plugin-button.scss';
3
3
  import {icons} from '../icons';
4
4
  import {A11yWrapper, OnClick} from '@playkit-js/common';
5
+
5
6
  const {Tooltip, Icon} = KalturaPlayer.ui.components;
7
+ const {withText, Text} = KalturaPlayer.ui.preacti18n;
8
+
9
+ const translates = ({isActive}: PluginButtonProps) => {
10
+ return {
11
+ label: isActive ? <Text id="transcript.hide_plugin">Hide Transcript</Text> : <Text id="transcript.show_plugin">Show Transcript</Text>
12
+ };
13
+ };
6
14
 
7
15
  interface PluginButtonProps {
8
16
  isActive: boolean;
@@ -10,7 +18,7 @@ interface PluginButtonProps {
10
18
  label?: string;
11
19
  }
12
20
 
13
- export const PluginButton = ({isActive, onClick, label}: PluginButtonProps) => {
21
+ export const PluginButton = withText(translates)(({isActive, onClick, label}: PluginButtonProps) => {
14
22
  return (
15
23
  <Tooltip label={label} type="bottom">
16
24
  <A11yWrapper onClick={onClick}>
@@ -26,4 +34,4 @@ export const PluginButton = ({isActive, onClick, label}: PluginButtonProps) => {
26
34
  </A11yWrapper>
27
35
  </Tooltip>
28
36
  );
29
- };
37
+ });
@@ -0,0 +1 @@
1
+ export * from "./popover";
@@ -0,0 +1,43 @@
1
+ @import '../../variables.scss';
2
+
3
+ .popover-container {
4
+ position: relative;
5
+ .popover-component {
6
+ background-color: #222222;
7
+ border-radius: 4px;
8
+ position: absolute;
9
+ right: 0px;
10
+ font-size: 15px;
11
+ display: block;
12
+ &.hidden {
13
+ display: none;
14
+ }
15
+ &.bottom {
16
+ top: 100%;
17
+ margin-top: 6px;
18
+ }
19
+ &.left {
20
+ right: 0px;
21
+ }
22
+ }
23
+ }
24
+ .popover-menu {
25
+ padding-top: 6px;
26
+ padding-bottom: 6px;
27
+ }
28
+ .popover-menu-item {
29
+ display: flex;
30
+ align-items: center;
31
+ padding: 9px 24px 9px 16px;
32
+ white-space: nowrap;
33
+ min-height: 30px;
34
+ line-height: 18px;
35
+ font-size: 15px;
36
+ &:hover {
37
+ cursor: pointer;
38
+ background-color: $semigray-color;
39
+ }
40
+ &:focus {
41
+ outline: 1px solid $focus-color;
42
+ }
43
+ }
@@ -0,0 +1,142 @@
1
+ import {h, Component, VNode} from 'preact';
2
+ import {A11yWrapper, OnClickEvent} from '@playkit-js/common';
3
+ import * as styles from './popover.scss';
4
+
5
+ const {Tooltip} = KalturaPlayer.ui.components;
6
+ const {ENTER, ESC, SPACE, TAB} = KalturaPlayer.ui.utils.KeyMap;
7
+
8
+ export interface PopoverMenuItem {
9
+ label?: string;
10
+ onMenuChosen: () => void;
11
+ }
12
+
13
+ interface PopoverProps {
14
+ label: string;
15
+ options: Array<PopoverMenuItem>;
16
+ children: VNode;
17
+ }
18
+
19
+ interface PopoverState {
20
+ open: boolean;
21
+ }
22
+
23
+ export class Popover extends Component<PopoverProps, PopoverState> {
24
+ private _controlElementRef: HTMLDivElement | null = null;
25
+ private _popoverElementRef: HTMLDivElement | null = null;
26
+ private _firstOptionElementRef: HTMLDivElement | null = null;
27
+
28
+ state = {
29
+ open: false
30
+ };
31
+
32
+ componentWillUnmount() {
33
+ this._removeListeners();
34
+ }
35
+
36
+ private _handleMouseEvent = (event: MouseEvent) => {
37
+ if (!this._controlElementRef?.contains(event.target as Node | null)) {
38
+ this._closePopover();
39
+ }
40
+ };
41
+
42
+ private _handleKeyboardEvent = (event: KeyboardEvent) => {
43
+ if (this._controlElementRef?.contains(event.target as Node | null) && [ENTER, SPACE].includes(event.keyCode)) {
44
+ // use handler of control element
45
+ event.preventDefault();
46
+ return;
47
+ }
48
+ if (this._popoverElementRef?.contains(event.target as Node | null) && event.keyCode !== ESC) {
49
+ // use handler of popover element
50
+ return;
51
+ }
52
+ this._closePopover();
53
+ };
54
+
55
+ private _openPopover = (byKeyboard?: boolean) => {
56
+ this.setState({open: true});
57
+ setTimeout(() => {
58
+ // add listeners after component got re-render
59
+ this._addListeners();
60
+ if (byKeyboard && this._firstOptionElementRef) {
61
+ this._firstOptionElementRef.focus();
62
+ }
63
+ });
64
+ };
65
+
66
+ private _closePopover = () => {
67
+ this._removeListeners();
68
+ this.setState({open: false});
69
+ };
70
+
71
+ private _togglePopover = (e: MouseEvent | KeyboardEvent, byKeyboard?: boolean) => {
72
+ if (this.state.open) {
73
+ this._closePopover();
74
+ } else {
75
+ this._openPopover(byKeyboard);
76
+ }
77
+ };
78
+ private _addListeners = () => {
79
+ document.addEventListener('click', this._handleMouseEvent);
80
+ document.addEventListener('keydown', this._handleKeyboardEvent);
81
+ };
82
+ private _removeListeners = () => {
83
+ document.removeEventListener('click', this._handleMouseEvent);
84
+ document.removeEventListener('keydown', this._handleKeyboardEvent);
85
+ };
86
+
87
+ private _handleClickOnOptoin = (cb: () => void) => (event: OnClickEvent, byKeyboard?: boolean) => {
88
+ this._closePopover();
89
+ cb();
90
+ if (byKeyboard) {
91
+ setTimeout(() => {});
92
+ }
93
+ };
94
+ render(props: PopoverProps) {
95
+ const {open} = this.state;
96
+ const content = <A11yWrapper onClick={this._togglePopover}>{props.children}</A11yWrapper>;
97
+ return (
98
+ <div className={styles.popoverContainer}>
99
+ <div
100
+ className="popover-anchor-container"
101
+ ref={node => {
102
+ this._controlElementRef = node;
103
+ }}>
104
+ {open ? (
105
+ content
106
+ ) : (
107
+ <Tooltip label={props.label} type="bottom">
108
+ {content}
109
+ </Tooltip>
110
+ )}
111
+ </div>
112
+ <div
113
+ aria-expanded={open}
114
+ ref={node => {
115
+ this._popoverElementRef = node;
116
+ }}
117
+ className={['popover', styles.popoverComponent, styles.bottom, styles.left, open ? '' : styles.hidden].join(' ')}>
118
+ <div className={styles.popoverMenu} role="menu">
119
+ {props.options.map((el, index) => {
120
+ return (
121
+ <A11yWrapper onClick={this._handleClickOnOptoin(el.onMenuChosen)}>
122
+ <div
123
+ tabIndex={0}
124
+ role="menuitem"
125
+ aria-label={el.label}
126
+ className={styles.popoverMenuItem}
127
+ ref={node => {
128
+ if (index === 0) {
129
+ this._firstOptionElementRef = node;
130
+ }
131
+ }}>
132
+ {el.label}
133
+ </div>
134
+ </A11yWrapper>
135
+ );
136
+ })}
137
+ </div>
138
+ </div>
139
+ </div>
140
+ );
141
+ }
142
+ }