@playkit-js/transcript 2.1.4 → 2.1.5-canary.16-1ac3e09
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/CHANGELOG.md +9 -0
- package/LICENSE +5 -5
- package/README.md +122 -24
- package/dist/1501adfdf5c835667ce7.svg +9 -0
- package/dist/301e7a199b2cd06c2edf.svg +9 -0
- package/dist/33bce27c0f546e80478c.svg +36 -0
- package/dist/6a4867d3d9170cc2a24d.svg +9 -0
- package/dist/73bab0af28a1c7aed29f.svg +9 -0
- package/dist/84087eb1cff72e5e6bd3.svg +9 -0
- package/dist/95d7192dc427afb678d0.svg +9 -0
- package/dist/cea5d6a7f050cbd199a1.svg +9 -0
- package/dist/d93f06ff32cdfcd016df.svg +9 -0
- package/dist/e5496f4c01207db44ffc.svg +9 -0
- package/dist/playkit-transcript.js +1 -31
- package/dist/playkit-transcript.js.map +1 -1
- package/package.json +53 -50
- package/src/components/a11y-wrapper/a11y-wrapper.ts +26 -0
- package/src/components/a11y-wrapper/index.ts +1 -0
- package/src/components/caption/caption.scss +1 -1
- package/src/components/caption/caption.tsx +118 -140
- package/src/components/caption/index.ts +1 -1
- package/src/components/caption-list/captionList.scss +8 -8
- package/src/components/caption-list/captionList.tsx +115 -117
- package/src/components/caption-list/index.ts +1 -1
- package/src/components/close-button/close-button.scss +11 -0
- package/src/components/close-button/index.tsx +23 -0
- package/src/components/download-print-menu/download-print-menu.scss +49 -48
- package/src/components/download-print-menu/download-print-menu.tsx +147 -125
- package/src/components/download-print-menu/index.ts +1 -1
- package/src/components/icons/index.ts +11 -0
- package/src/components/plugin-button/plugin-button.scss +26 -0
- package/src/components/plugin-button/plugin-button.tsx +29 -0
- package/src/components/popover-menu/index.ts +1 -1
- package/src/components/popover-menu/popover-menu.scss +3 -3
- package/src/components/popover-menu/popover-menu.tsx +25 -25
- package/src/components/search/index.ts +1 -1
- package/src/components/search/search.scss +1 -1
- package/src/components/search/search.tsx +137 -144
- package/src/components/spinner/index.ts +1 -1
- package/src/components/spinner/spinner.scss +58 -50
- package/src/components/spinner/spinner.tsx +9 -9
- package/src/components/transcript/index.ts +1 -1
- package/src/components/transcript/transcript.scss +9 -33
- package/src/components/transcript/transcript.tsx +333 -454
- package/src/global.d.ts +6 -6
- package/src/index.ts +13 -1
- package/src/transcript-plugin.scss +3 -3
- package/src/transcript-plugin.tsx +210 -391
- package/src/types/index.ts +3 -0
- package/src/types/transcript-config.ts +11 -0
- package/src/types/transcript-item-data.ts +29 -0
- package/src/types/types-ui.ts +11 -0
- package/src/utils/debounce.ts +36 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/object-utils.ts +34 -0
- package/src/utils/popover/popover.scss +30 -0
- package/src/utils/popover/popover.tsx +178 -0
- package/src/utils/utils.ts +86 -0
- package/src/variables.scss +14 -0
- package/src/assets/close.svg +0 -10
- package/src/utils.ts +0 -192
|
@@ -1,132 +1,130 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { CaptionItem, HOUR } from "../../utils";
|
|
1
|
+
import {h, Component} from 'preact';
|
|
2
|
+
import {HOUR} from '../../utils';
|
|
3
|
+
import {Caption} from '../caption';
|
|
4
|
+
import * as styles from './captionList.scss';
|
|
5
|
+
import {HighlightedMap, CuePointData} from '../../types';
|
|
7
6
|
|
|
8
|
-
const {
|
|
7
|
+
const {End, Home} = KalturaPlayer.ui.utils.KeyMap;
|
|
9
8
|
|
|
10
|
-
interface
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
activeSearchIndex: number;
|
|
17
|
-
captionProps: CaptionProps;
|
|
9
|
+
export interface CaptionProps {
|
|
10
|
+
showTime: boolean;
|
|
11
|
+
searchLength: number;
|
|
12
|
+
scrollTo(el: HTMLElement): void;
|
|
13
|
+
scrollToSearchMatch(el: HTMLElement): void;
|
|
14
|
+
videoDuration: number;
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
17
|
+
export interface Props {
|
|
18
|
+
data: Array<CuePointData>;
|
|
19
|
+
onSeek: (n: CuePointData) => void;
|
|
20
|
+
autoScroll?: boolean;
|
|
21
|
+
onScroll: (n: number) => void;
|
|
22
|
+
widgetWidth: number;
|
|
23
|
+
highlightedMap: HighlightedMap;
|
|
24
|
+
showItemsIcons: boolean;
|
|
25
|
+
listDataContainCaptions?: boolean;
|
|
26
|
+
searchActive: boolean;
|
|
27
|
+
isAutoScrollEnabled: boolean;
|
|
28
|
+
activeSearchIndex: number;
|
|
29
|
+
searchMap: Record<string, Record<string, number>>;
|
|
30
|
+
captionProps: CaptionProps;
|
|
31
|
+
}
|
|
32
|
+
export class CaptionList extends Component<Props> {
|
|
33
|
+
private _currentCaptionRef: any = null;
|
|
34
|
+
private _firstCaptionRef: any = null;
|
|
35
|
+
private _lastCaptionRef: any = null;
|
|
36
|
+
shouldComponentUpdate(nextProps: Readonly<Props>) {
|
|
37
|
+
const {highlightedMap, data, searchMap, activeSearchIndex, isAutoScrollEnabled, captionProps} = this.props;
|
|
38
|
+
if (
|
|
39
|
+
highlightedMap !== nextProps.highlightedMap ||
|
|
40
|
+
data !== nextProps.data ||
|
|
41
|
+
searchMap !== nextProps.searchMap ||
|
|
42
|
+
activeSearchIndex !== nextProps.activeSearchIndex ||
|
|
43
|
+
isAutoScrollEnabled !== nextProps.isAutoScrollEnabled ||
|
|
44
|
+
captionProps.videoDuration !== nextProps.captionProps.videoDuration
|
|
45
|
+
) {
|
|
46
|
+
return true;
|
|
44
47
|
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
private _handleClick = (caption: CuePointData) => () => {
|
|
52
|
+
const {onSeek} = this.props;
|
|
53
|
+
onSeek(caption);
|
|
54
|
+
};
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
private _getShouldScroll = (captionId: string) => {
|
|
57
|
+
const {isAutoScrollEnabled, highlightedMap} = this.props;
|
|
58
|
+
return isAutoScrollEnabled && highlightedMap[captionId];
|
|
59
|
+
};
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
private _getShouldScrollToSearchMatch = (captionId: string) => {
|
|
62
|
+
const {isAutoScrollEnabled, searchMap, activeSearchIndex} = this.props;
|
|
63
|
+
return !isAutoScrollEnabled && searchMap[captionId] && searchMap[captionId][activeSearchIndex] !== undefined;
|
|
64
|
+
};
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
return searchProps;
|
|
66
|
+
private _getSearchProps = (captionId: string) => {
|
|
67
|
+
const {searchMap, activeSearchIndex, captionProps} = this.props;
|
|
68
|
+
const searchProps: any = {};
|
|
69
|
+
if (searchMap[captionId]) {
|
|
70
|
+
searchProps.indexMap = searchMap[captionId];
|
|
71
|
+
searchProps.activeSearchIndex = activeSearchIndex;
|
|
72
|
+
searchProps.searchLength = captionProps.searchLength;
|
|
70
73
|
}
|
|
74
|
+
return searchProps;
|
|
75
|
+
};
|
|
71
76
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
...this._getSearchProps(id)
|
|
92
|
-
}
|
|
93
|
-
return newCaptionProps;
|
|
94
|
-
}
|
|
77
|
+
private _getCaptionProps = (captionData: CuePointData) => {
|
|
78
|
+
const {highlightedMap, captionProps, isAutoScrollEnabled} = this.props;
|
|
79
|
+
const {id}: {id: string} = captionData;
|
|
80
|
+
const newCaptionProps = {
|
|
81
|
+
showTime: captionProps.showTime,
|
|
82
|
+
scrollTo: captionProps.scrollTo,
|
|
83
|
+
scrollToSearchMatch: captionProps.scrollToSearchMatch,
|
|
84
|
+
key: id,
|
|
85
|
+
onClick: this._handleClick(captionData),
|
|
86
|
+
caption: captionData,
|
|
87
|
+
highlighted: highlightedMap,
|
|
88
|
+
longerThanHour: captionProps.videoDuration >= HOUR,
|
|
89
|
+
shouldScroll: this._getShouldScroll(id),
|
|
90
|
+
shouldScrollToSearchMatch: this._getShouldScrollToSearchMatch(id),
|
|
91
|
+
isAutoScrollEnabled,
|
|
92
|
+
...this._getSearchProps(id)
|
|
93
|
+
};
|
|
94
|
+
return newCaptionProps;
|
|
95
|
+
};
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
97
|
+
private _handleKeyUp = (event: KeyboardEvent) => {
|
|
98
|
+
if (event.keyCode === End) {
|
|
99
|
+
this._lastCaptionRef?._hotspotRef?.focus();
|
|
100
|
+
} else if (event.keyCode === Home) {
|
|
101
|
+
this._firstCaptionRef?._hotspotRef?.focus();
|
|
102
102
|
}
|
|
103
|
+
};
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
</div>
|
|
130
|
-
);
|
|
131
|
-
}
|
|
105
|
+
render() {
|
|
106
|
+
const {data} = this.props;
|
|
107
|
+
return (
|
|
108
|
+
<div className={styles.transcriptWrapper} onKeyUp={this._handleKeyUp}>
|
|
109
|
+
{data.map((captionData, index) => {
|
|
110
|
+
const captionProps = this._getCaptionProps(captionData);
|
|
111
|
+
return (
|
|
112
|
+
<Caption
|
|
113
|
+
ref={node => {
|
|
114
|
+
if (index === 0) {
|
|
115
|
+
this._firstCaptionRef = node;
|
|
116
|
+
} else if (index === data.length - 1) {
|
|
117
|
+
this._lastCaptionRef = node;
|
|
118
|
+
}
|
|
119
|
+
if (captionProps.highlighted) {
|
|
120
|
+
this._currentCaptionRef = node;
|
|
121
|
+
}
|
|
122
|
+
}}
|
|
123
|
+
{...captionProps}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
})}
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
132
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from
|
|
1
|
+
export * from './captionList';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {h} from 'preact';
|
|
2
|
+
import * as styles from './close-button.scss';
|
|
3
|
+
import {A11yWrapper} from '../a11y-wrapper/a11y-wrapper';
|
|
4
|
+
import {icons} from '../icons';
|
|
5
|
+
const {Icon} = KalturaPlayer.ui.components;
|
|
6
|
+
|
|
7
|
+
interface CloseButtonProps {
|
|
8
|
+
onClick: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const CloseButton = (props: CloseButtonProps) => (
|
|
12
|
+
<A11yWrapper onClick={props.onClick}>
|
|
13
|
+
<button className={styles.closeBtn} tabIndex={1}>
|
|
14
|
+
<Icon
|
|
15
|
+
id="transcript-plugin-close-button"
|
|
16
|
+
height={icons.BigSize}
|
|
17
|
+
width={icons.BigSize}
|
|
18
|
+
viewBox={`0 0 ${icons.BigSize} ${icons.BigSize}`}
|
|
19
|
+
path={icons.CLOSE_ICON}
|
|
20
|
+
/>
|
|
21
|
+
</button>
|
|
22
|
+
</A11yWrapper>
|
|
23
|
+
);
|
|
@@ -1,55 +1,56 @@
|
|
|
1
|
-
@import
|
|
1
|
+
@import '../../variables.scss';
|
|
2
2
|
|
|
3
3
|
.download-print-button {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
display: inline-block;
|
|
5
|
+
width: 36px;
|
|
6
|
+
height: 36px;
|
|
7
|
+
color: $white-color;
|
|
8
|
+
border: none;
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
padding: 0;
|
|
11
|
+
background: none;
|
|
12
|
+
border-radius: 4px;
|
|
13
|
+
outline-offset: 0 -1px;
|
|
14
|
+
&:hover,
|
|
15
|
+
&:active {
|
|
16
|
+
border-radius: 4px;
|
|
17
|
+
background-color: rgba(0, 0, 0, 0.8);
|
|
18
|
+
}
|
|
19
|
+
&:focus {
|
|
20
|
+
outline: 1px solid $focus-color;
|
|
21
|
+
}
|
|
22
|
+
.icon {
|
|
23
|
+
width: 100%;
|
|
24
|
+
height: 100%;
|
|
25
|
+
background-position: center;
|
|
26
|
+
background-size: cover;
|
|
27
|
+
}
|
|
28
|
+
.download-icon {
|
|
29
|
+
background-image: url('../../assets/download.svg');
|
|
14
30
|
&:active {
|
|
15
|
-
|
|
16
|
-
background-color: rgba(0, 0, 0, 0.8);
|
|
17
|
-
}
|
|
18
|
-
&:focus {
|
|
19
|
-
outline: 1px solid $focus-color;
|
|
20
|
-
}
|
|
21
|
-
.icon {
|
|
22
|
-
width: 100%;
|
|
23
|
-
height: 100%;
|
|
24
|
-
background-position: center;
|
|
25
|
-
background-size: cover;
|
|
31
|
+
background-image: url('../../assets/download-over.svg');
|
|
26
32
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
.print-icon {
|
|
34
|
-
background-image: url('../../assets/print.svg');
|
|
35
|
-
&:active {
|
|
36
|
-
background-image: url('../../assets/print-over.svg');
|
|
37
|
-
}
|
|
33
|
+
}
|
|
34
|
+
.print-icon {
|
|
35
|
+
background-image: url('../../assets/print.svg');
|
|
36
|
+
&:active {
|
|
37
|
+
background-image: url('../../assets/print-over.svg');
|
|
38
38
|
}
|
|
39
|
+
}
|
|
39
40
|
}
|
|
40
41
|
.popover-menu-item {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
padding: 9px 24px 9px 16px;
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
min-height: 30px;
|
|
47
|
+
line-height: 18px;
|
|
48
|
+
font-size: 15px;
|
|
49
|
+
&:hover {
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
background-color: $semigray-color;
|
|
52
|
+
}
|
|
53
|
+
&:focus {
|
|
54
|
+
outline: 1px solid $focus-color;
|
|
55
|
+
}
|
|
56
|
+
}
|