@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.
Files changed (61) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +5 -5
  3. package/README.md +122 -24
  4. package/dist/1501adfdf5c835667ce7.svg +9 -0
  5. package/dist/301e7a199b2cd06c2edf.svg +9 -0
  6. package/dist/33bce27c0f546e80478c.svg +36 -0
  7. package/dist/6a4867d3d9170cc2a24d.svg +9 -0
  8. package/dist/73bab0af28a1c7aed29f.svg +9 -0
  9. package/dist/84087eb1cff72e5e6bd3.svg +9 -0
  10. package/dist/95d7192dc427afb678d0.svg +9 -0
  11. package/dist/cea5d6a7f050cbd199a1.svg +9 -0
  12. package/dist/d93f06ff32cdfcd016df.svg +9 -0
  13. package/dist/e5496f4c01207db44ffc.svg +9 -0
  14. package/dist/playkit-transcript.js +1 -31
  15. package/dist/playkit-transcript.js.map +1 -1
  16. package/package.json +53 -50
  17. package/src/components/a11y-wrapper/a11y-wrapper.ts +26 -0
  18. package/src/components/a11y-wrapper/index.ts +1 -0
  19. package/src/components/caption/caption.scss +1 -1
  20. package/src/components/caption/caption.tsx +118 -140
  21. package/src/components/caption/index.ts +1 -1
  22. package/src/components/caption-list/captionList.scss +8 -8
  23. package/src/components/caption-list/captionList.tsx +115 -117
  24. package/src/components/caption-list/index.ts +1 -1
  25. package/src/components/close-button/close-button.scss +11 -0
  26. package/src/components/close-button/index.tsx +23 -0
  27. package/src/components/download-print-menu/download-print-menu.scss +49 -48
  28. package/src/components/download-print-menu/download-print-menu.tsx +147 -125
  29. package/src/components/download-print-menu/index.ts +1 -1
  30. package/src/components/icons/index.ts +11 -0
  31. package/src/components/plugin-button/plugin-button.scss +26 -0
  32. package/src/components/plugin-button/plugin-button.tsx +29 -0
  33. package/src/components/popover-menu/index.ts +1 -1
  34. package/src/components/popover-menu/popover-menu.scss +3 -3
  35. package/src/components/popover-menu/popover-menu.tsx +25 -25
  36. package/src/components/search/index.ts +1 -1
  37. package/src/components/search/search.scss +1 -1
  38. package/src/components/search/search.tsx +137 -144
  39. package/src/components/spinner/index.ts +1 -1
  40. package/src/components/spinner/spinner.scss +58 -50
  41. package/src/components/spinner/spinner.tsx +9 -9
  42. package/src/components/transcript/index.ts +1 -1
  43. package/src/components/transcript/transcript.scss +9 -33
  44. package/src/components/transcript/transcript.tsx +333 -454
  45. package/src/global.d.ts +6 -6
  46. package/src/index.ts +13 -1
  47. package/src/transcript-plugin.scss +3 -3
  48. package/src/transcript-plugin.tsx +210 -391
  49. package/src/types/index.ts +3 -0
  50. package/src/types/transcript-config.ts +11 -0
  51. package/src/types/transcript-item-data.ts +29 -0
  52. package/src/types/types-ui.ts +11 -0
  53. package/src/utils/debounce.ts +36 -0
  54. package/src/utils/index.ts +4 -0
  55. package/src/utils/object-utils.ts +34 -0
  56. package/src/utils/popover/popover.scss +30 -0
  57. package/src/utils/popover/popover.tsx +178 -0
  58. package/src/utils/utils.ts +86 -0
  59. package/src/variables.scss +14 -0
  60. package/src/assets/close.svg +0 -10
  61. package/src/utils.ts +0 -192
@@ -1,165 +1,158 @@
1
- import { h, Component } from "preact";
2
- import * as styles from "./search.scss";
1
+ import {h, Component} from 'preact';
2
+ import * as styles from './search.scss';
3
+ import {debounce} from '../../utils';
4
+ const DEBOUNCE_TIMEOUT = 300;
3
5
 
4
6
  export interface SearchProps {
5
- onChange(value: string): void;
6
- onSearchIndexChange(value: number): void;
7
- value: string;
8
- activeSearchIndex: number;
9
- totalSearchResults: number;
10
- kitchenSinkActive: boolean;
11
- toggledWithEnter: boolean;
7
+ onChange(value: string): void;
8
+ searchQuery: string;
9
+ kitchenSinkActive: boolean;
10
+ toggledWithEnter: boolean;
11
+
12
+ onSearchIndexChange: (index: number) => void;
13
+ value: string;
14
+ activeSearchIndex: number;
15
+ totalSearchResults: number;
12
16
  }
13
17
 
14
18
  interface SearchState {
15
- active: boolean;
16
- focused: boolean;
19
+ active: boolean;
20
+ focused: boolean;
17
21
  }
18
22
 
19
23
  export class Search extends Component<SearchProps, SearchState> {
20
- state: SearchState = {
21
- active: false,
22
- focused: false,
24
+ state: SearchState = {
25
+ active: false,
26
+ focused: false
27
+ };
28
+ private _inputRef: null | HTMLInputElement = null;
29
+ private _focusedByMouse = false;
30
+ private _debouncedOnChange: (value: string) => void;
31
+ constructor(props: SearchProps) {
32
+ super(props);
33
+ this._debouncedOnChange = debounce(props.onChange, DEBOUNCE_TIMEOUT);
34
+ this.state = {
35
+ active: false,
36
+ focused: false
23
37
  };
24
- private _inputRef: null | HTMLInputElement = null;
25
- private _focusedByMouse = false;
38
+ }
26
39
 
27
- shouldComponentUpdate(
28
- nextProps: Readonly<SearchProps>,
29
- nextState: Readonly<SearchState>
40
+ shouldComponentUpdate(nextProps: Readonly<SearchProps>, nextState: Readonly<SearchState>) {
41
+ const {value, activeSearchIndex, totalSearchResults, kitchenSinkActive} = this.props;
42
+ if (
43
+ value !== nextProps.value ||
44
+ activeSearchIndex !== nextProps.activeSearchIndex ||
45
+ totalSearchResults !== nextProps.totalSearchResults ||
46
+ kitchenSinkActive !== nextProps.kitchenSinkActive ||
47
+ this.state.active !== nextState.active
30
48
  ) {
31
- const { value, activeSearchIndex, totalSearchResults, kitchenSinkActive } = this.props;
32
- if (
33
- value !== nextProps.value ||
34
- activeSearchIndex !== nextProps.activeSearchIndex ||
35
- totalSearchResults !== nextProps.totalSearchResults ||
36
- kitchenSinkActive !== nextProps.kitchenSinkActive ||
37
- this.state.active !== nextState.active
38
- ) {
39
- return true;
40
- }
41
- return false;
49
+ return true;
42
50
  }
43
- componentDidUpdate(previousProps: Readonly<SearchProps>): void {
44
- const { kitchenSinkActive, toggledWithEnter } = this.props;
45
- if (!previousProps.kitchenSinkActive && kitchenSinkActive && toggledWithEnter) {
46
- this._inputRef?.focus();
47
- }
51
+ return false;
52
+ }
53
+ componentDidUpdate(previousProps: Readonly<SearchProps>): void {
54
+ const {kitchenSinkActive, toggledWithEnter} = this.props;
55
+ if (!previousProps.kitchenSinkActive && kitchenSinkActive && toggledWithEnter) {
56
+ this._inputRef?.focus();
48
57
  }
49
- private _handleOnChange = (e: any) => {
50
- this.props.onChange(e.target.value);
51
- };
52
-
53
- private _onClear = (event: MouseEvent) => {
54
- if (event.x !== 0 && event.y !== 0) {
55
- this._focusedByMouse = true;
56
- }
57
- this._inputRef?.focus();
58
- this.props.onChange("");
59
- };
58
+ }
60
59
 
61
- private _onFocus = () => {
62
- this.setState({
63
- active: true,
64
- focused: !this._focusedByMouse,
65
- });
66
- this._focusedByMouse = false;
67
- }
60
+ private _handleOnChange = (e: any) => {
61
+ this.props.onChange(e.target.value);
62
+ };
68
63
 
69
- private _onBlur = () => {
70
- this.setState({
71
- active: false,
72
- focused: false
73
- });
64
+ private _onClear = (event: MouseEvent) => {
65
+ if (event.x !== 0 && event.y !== 0) {
66
+ this._focusedByMouse = true;
74
67
  }
68
+ this._inputRef?.focus();
69
+ this.props.onChange('');
70
+ };
75
71
 
76
- private _goToNextSearchResult = () => {
77
- const { activeSearchIndex, totalSearchResults, onSearchIndexChange } = this.props;
78
- if (totalSearchResults === 0) {
79
- return;
80
- }
81
- let index = 0;
82
- if (activeSearchIndex !== totalSearchResults) {
83
- index = this.props.activeSearchIndex + 1;
84
- } else {
85
- index = 1;
86
- }
87
- onSearchIndexChange(index);
88
- };
89
- private _goToPrevSearchResult = () => {
90
- const { activeSearchIndex, totalSearchResults, onSearchIndexChange } = this.props;
91
- let index = 0;
92
- if (activeSearchIndex !== 1) {
93
- index = activeSearchIndex - 1;
94
- } else {
95
- index = totalSearchResults;
96
- }
97
- onSearchIndexChange(index);
98
- };
72
+ private _onFocus = () => {
73
+ this.setState({
74
+ active: true,
75
+ focused: !this._focusedByMouse
76
+ });
77
+ this._focusedByMouse = false;
78
+ };
99
79
 
100
- _handleMouseDown = () => {
101
- this._focusedByMouse = true;
102
- };
80
+ private _onBlur = () => {
81
+ this.setState({
82
+ active: false,
83
+ focused: false
84
+ });
85
+ };
103
86
 
104
- render() {
105
- const { value, activeSearchIndex, totalSearchResults } = this.props;
106
- return (
107
- <div className={[
108
- styles.searchWrapper,
109
- (value || this.state.active) ? styles.active : "",
110
- this.state.focused ? styles.focused : "",
111
- ].join(" ")}>
112
- <div className={styles.searchIcon} />
113
- <input
114
- className={styles.searchInput}
115
- placeholder={"Search in Transcript"}
116
- value={value}
117
- onInput={this._handleOnChange}
118
- onFocus={this._onFocus}
119
- onBlur={this._onBlur}
120
- onMouseDown={this._handleMouseDown}
121
- tabIndex={1}
122
- ref={(node) => {
123
- this._inputRef = node;
124
- }}
125
- />
126
- {value && (
127
- <button
128
- className={styles.clearIcon}
129
- onClick={this._onClear}
130
- tabIndex={1}
131
- />
132
- )}
133
- {value && (
134
- <div className={styles.searchResults}>
135
- {`${
136
- totalSearchResults > 0
137
- ? `${activeSearchIndex}/${totalSearchResults}`
138
- : "0/0"
139
- }`}
140
- </div>
141
- )}
142
- <div className={styles.prevNextWrapper}>
143
- {value && (
144
- <button
145
- tabIndex={1}
146
- className={`${styles.prevNextButton} ${styles.prevButton} ${
147
- totalSearchResults === 0 ? styles.disabled : ""
148
- }`}
149
- onClick={this._goToPrevSearchResult}
150
- />
151
- )}
152
- {value && (
153
- <button
154
- tabIndex={1}
155
- className={`${styles.prevNextButton} ${styles.nextButton} ${
156
- totalSearchResults === 0 ? styles.disabled : ""
157
- }`}
158
- onClick={this._goToNextSearchResult}
159
- />
160
- )}
161
- </div>
162
- </div>
163
- );
87
+ private _goToNextSearchResult = () => {
88
+ const {activeSearchIndex, totalSearchResults, onSearchIndexChange} = this.props;
89
+ if (totalSearchResults === 0) {
90
+ return;
91
+ }
92
+ let index = 0;
93
+ if (activeSearchIndex !== totalSearchResults) {
94
+ index = this.props.activeSearchIndex + 1;
95
+ } else {
96
+ index = 1;
164
97
  }
98
+ onSearchIndexChange(index);
99
+ };
100
+ private _goToPrevSearchResult = () => {
101
+ const {activeSearchIndex, totalSearchResults, onSearchIndexChange} = this.props;
102
+ let index = 0;
103
+ if (activeSearchIndex !== 1) {
104
+ index = activeSearchIndex - 1;
105
+ } else {
106
+ index = totalSearchResults;
107
+ }
108
+ onSearchIndexChange(index);
109
+ };
110
+
111
+ _handleMouseDown = () => {
112
+ this._focusedByMouse = true;
113
+ };
114
+
115
+ render() {
116
+ const {searchQuery, totalSearchResults, activeSearchIndex} = this.props;
117
+ return (
118
+ <div
119
+ className={[styles.searchWrapper, searchQuery || this.state.active ? styles.active : '', this.state.focused ? styles.focused : ''].join(' ')}
120
+ >
121
+ <div className={styles.searchIcon} />
122
+ <input
123
+ className={styles.searchInput}
124
+ placeholder={'Search in Transcript'}
125
+ value={searchQuery}
126
+ onInput={this._handleOnChange}
127
+ onFocus={this._onFocus}
128
+ onBlur={this._onBlur}
129
+ onMouseDown={this._handleMouseDown}
130
+ tabIndex={1}
131
+ ref={node => {
132
+ this._inputRef = node;
133
+ }}
134
+ />
135
+ {searchQuery && <button className={styles.clearIcon} onClick={this._onClear} tabIndex={1} />}
136
+ {searchQuery && (
137
+ <div className={styles.searchResults}>{`${totalSearchResults > 0 ? `${activeSearchIndex}/${totalSearchResults}` : '0/0'}`}</div>
138
+ )}
139
+ <div className={styles.prevNextWrapper}>
140
+ {searchQuery && (
141
+ <button
142
+ tabIndex={1}
143
+ className={`${styles.prevNextButton} ${styles.prevButton} ${totalSearchResults === 0 ? styles.disabled : ''}`}
144
+ onClick={this._goToPrevSearchResult}
145
+ />
146
+ )}
147
+ {searchQuery && (
148
+ <button
149
+ tabIndex={1}
150
+ className={`${styles.prevNextButton} ${styles.nextButton} ${totalSearchResults === 0 ? styles.disabled : ''}`}
151
+ onClick={this._goToNextSearchResult}
152
+ />
153
+ )}
154
+ </div>
155
+ </div>
156
+ );
157
+ }
165
158
  }
@@ -1 +1 @@
1
- export * from "./spinner";
1
+ export * from './spinner';
@@ -1,57 +1,65 @@
1
1
  .spinner-ball {
2
- position: relative;
3
- display: flex;
4
- align-items: center;
5
- width: 100%;
6
- height: 100%;
7
- max-width: 184px;
8
- max-height: 184px;
9
- margin: 4px 0 8px 0;
10
- background-size: contain;
11
- background-repeat: no-repeat;
12
- background-position: center;
13
- background-image: url('../../assets/loader.svg');
2
+ position: relative;
3
+ display: flex;
4
+ align-items: center;
5
+ width: 100%;
6
+ height: 100%;
7
+ max-width: 184px;
8
+ max-height: 184px;
9
+ margin: 4px 0 8px 0;
10
+ background-size: contain;
11
+ background-repeat: no-repeat;
12
+ background-position: center;
13
+ background-image: url('../../assets/loader.svg');
14
14
 
15
- animation: icon-bounce 2.0s infinite ease-in-out;
15
+ animation: icon-bounce 2s infinite ease-in-out;
16
+ }
17
+
18
+ .bounce-frame {
19
+ width: 100%;
20
+ height: 100%;
21
+ min-width: 184px;
22
+ min-height: 184px;
23
+ border-radius: 50%;
24
+ background-color: #cccccc;
25
+ opacity: 0.2;
26
+
27
+ -webkit-animation: frame-bounce 2s infinite ease-in-out;
28
+ animation: frame-bounce 2s infinite ease-in-out;
29
+ }
30
+
31
+ @keyframes icon-bounce {
32
+ 0%,
33
+ 100% {
34
+ opacity: 0.3;
35
+ }
36
+ 50% {
37
+ opacity: 1;
38
+ }
39
+ }
40
+
41
+ @-webkit-keyframes frame-bounce {
42
+ 0%,
43
+ 100% {
44
+ -webkit-transform: scale(1);
45
+ opacity: 0.1;
16
46
  }
17
-
18
- .bounce-frame {
19
- width: 100%;
20
- height: 100%;
21
- min-width: 184px;
22
- min-height: 184px;
23
- border-radius: 50%;
24
- background-color: #cccccc;
25
- opacity: 0.2;
26
-
27
- -webkit-animation: frame-bounce 2.0s infinite ease-in-out;
28
- animation: frame-bounce 2.0s infinite ease-in-out;
47
+ 50% {
48
+ -webkit-transform: scale(1.3);
49
+ opacity: 0.1;
29
50
  }
51
+ }
30
52
 
31
- @keyframes icon-bounce {
32
- 0%, 100% { opacity: 0.3 }
33
- 50% { opacity: 1 }
53
+ @keyframes frame-bounce {
54
+ 0%,
55
+ 100% {
56
+ opacity: 0.1;
57
+ transform: scale(1);
58
+ -webkit-transform: scale(1);
34
59
  }
35
-
36
- @-webkit-keyframes frame-bounce {
37
- 0%, 100% {
38
- -webkit-transform: scale(1.0);
39
- opacity: 0.1;
40
- }
41
- 50% {
42
- -webkit-transform: scale(1.3);
43
- opacity: 0.1;
44
- }
60
+ 50% {
61
+ opacity: 0.25;
62
+ transform: scale(1.3);
63
+ -webkit-transform: scale(1.3);
45
64
  }
46
-
47
- @keyframes frame-bounce {
48
- 0%, 100% {
49
- opacity: 0.1;
50
- transform: scale(1.0);
51
- -webkit-transform: scale(1.0);
52
- } 50% {
53
- opacity: 0.25;
54
- transform: scale(1.3);
55
- -webkit-transform: scale(1.3);
56
- }
57
- }
65
+ }
@@ -1,12 +1,12 @@
1
- import { h, Component } from "preact";
2
- import * as styles from "./spinner.scss";
1
+ import {h, Component} from 'preact';
2
+ import * as styles from './spinner.scss';
3
3
 
4
4
  export class Spinner extends Component {
5
- render() {
6
- return (
7
- <div className={styles.spinnerBall}>
8
- <div className={styles.bounceFrame} />
9
- </div>
10
- );
11
- }
5
+ render() {
6
+ return (
7
+ <div className={styles.spinnerBall}>
8
+ <div className={styles.bounceFrame} />
9
+ </div>
10
+ );
11
+ }
12
12
  }
@@ -1 +1 @@
1
- export * from "./transcript";
1
+ export * from './transcript';
@@ -1,21 +1,5 @@
1
1
  @import '../../variables.scss';
2
2
 
3
- /* TODO: (1) remove this once 3rd party cross-browser custom scroll bar is Added */
4
- .body::-webkit-scrollbar {
5
- width: 4px;
6
- }
7
-
8
- /* Track TODO: as (1)*/
9
- .body::-webkit-scrollbar-track {
10
- background: rgba(33, 33, 33, 0.9);
11
- }
12
-
13
- /* Handle TODO: as (1) */
14
- .body::-webkit-scrollbar-thumb {
15
- border-radius: 3px;
16
- background-color: rgba(255, 255, 255, 0.3);
17
- }
18
-
19
3
  .hidden {
20
4
  visibility: hidden;
21
5
  }
@@ -29,6 +13,7 @@
29
13
  width: 100%;
30
14
  position: absolute;
31
15
  background-color: $root-background;
16
+ z-index: 1;
32
17
  .skip-transcript-button {
33
18
  position: absolute;
34
19
  top: -1000px;
@@ -51,6 +36,11 @@
51
36
  outline: none !important; // prevent focus styles inherited from playkit-player.playkit-nav
52
37
  }
53
38
  }
39
+
40
+ * {
41
+ font-family: sans-serif;
42
+ font-style: normal;
43
+ }
54
44
  }
55
45
 
56
46
  .global-container {
@@ -76,20 +66,6 @@
76
66
  padding-right: 22px;
77
67
  }
78
68
  }
79
- .close-button {
80
- position: absolute;
81
- top: 8px;
82
- right: 0;
83
- width: 32px;
84
- height: 32px;
85
- min-width: 32px;
86
- margin: 0 8px;
87
- cursor: pointer;
88
- background-image: url('../../assets/close.svg');
89
- background-color: transparent;
90
- border: none;
91
- padding: 0;
92
- }
93
69
 
94
70
  .body {
95
71
  position: relative;
@@ -98,6 +74,7 @@
98
74
  overflow-y: auto;
99
75
  text-align: center;
100
76
  overflow-x: hidden;
77
+ @include plugin-scrollbar();
101
78
  }
102
79
 
103
80
  .loading-wrapper,
@@ -117,7 +94,6 @@
117
94
  background-size: contain;
118
95
  background-repeat: no-repeat;
119
96
  background-position: center;
120
- background-image: url('../../assets/error.svg');
121
97
  }
122
98
  .error-main-text {
123
99
  font-size: 1.3em;
@@ -142,7 +118,7 @@
142
118
  opacity: 0;
143
119
  position: absolute;
144
120
  right: 12px;
145
- bottom: 12px;
121
+ bottom: 25px;
146
122
  width: 32px;
147
123
  height: 32px;
148
124
  padding: 0;
@@ -160,4 +136,4 @@
160
136
 
161
137
  .autoscroll-button-visible {
162
138
  opacity: 1;
163
- }
139
+ }