@instructure/canvas-rce 7.3.1 → 8.0.0

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 (155) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/{es/rce/plugins/shared/ai_tools/index.js → __mocks__/@instructure/ui-media-player/_mockUiMediaPlayer.js} +4 -4
  3. package/__tests__/common/mimeClass.test.js +25 -1
  4. package/__tests__/rcs/api.test.js +280 -251
  5. package/es/canvasFileBrowser/FileBrowser.d.ts +2 -2
  6. package/es/canvasFileBrowser/FileBrowser.js +8 -7
  7. package/es/common/mimeClass.js +3 -1
  8. package/es/defaultTinymceConfig.js +47 -49
  9. package/es/enhance-user-content/enhance_user_content.js +6 -8
  10. package/es/enhance-user-content/index.d.ts +3 -1
  11. package/es/enhance-user-content/index.js +3 -1
  12. package/es/enhance-user-content/youtube_overlay.js +18 -0
  13. package/es/getThemeVars.d.ts +1 -1
  14. package/es/getThemeVars.js +23 -26
  15. package/es/rce/KeyboardShortcutModal.js +1 -1
  16. package/es/rce/RCE.d.ts +9 -0
  17. package/es/rce/RCE.js +4 -0
  18. package/es/rce/RCEGlobals.d.ts +2 -0
  19. package/es/rce/RCEGlobals.js +1 -0
  20. package/es/rce/RCEVariants.d.ts +1 -2
  21. package/es/rce/RCEVariants.js +1 -2
  22. package/es/rce/RCEWrapper.d.ts +6 -16
  23. package/es/rce/RCEWrapper.js +18 -87
  24. package/es/rce/RCEWrapper.utils.d.ts +1 -1
  25. package/es/rce/RCEWrapperProps.d.ts +2 -1
  26. package/es/rce/RCEWrapperProps.js +2 -1
  27. package/es/rce/StatusBar.d.ts +0 -1
  28. package/es/rce/StatusBar.js +3 -28
  29. package/es/rce/plugins/instructure_equation/EquationEditorModal/advancedOnlySyntax.d.ts +2 -1
  30. package/es/rce/plugins/instructure_equation/EquationEditorModal/advancedOnlySyntax.js +3 -1
  31. package/es/rce/plugins/instructure_equation/EquationEditorModal/index.d.ts +1 -0
  32. package/es/rce/plugins/instructure_equation/EquationEditorModal/index.js +12 -2
  33. package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/ImageOptions.js +2 -2
  34. package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/ImageSection.js +3 -3
  35. package/es/rce/plugins/instructure_icon_maker/svg/constants.d.ts +20 -5
  36. package/es/rce/plugins/instructure_icon_maker/svg/utils.d.ts +1 -1
  37. package/es/rce/plugins/instructure_icon_maker/utils/IconMakerFormHasChanges.js +2 -2
  38. package/es/rce/plugins/instructure_image/ImageEmbedOptions.d.ts +0 -2
  39. package/es/rce/plugins/instructure_image/ImageEmbedOptions.js +2 -9
  40. package/es/rce/plugins/instructure_paste/plugin.js +18 -12
  41. package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.d.ts +1 -1
  42. package/es/rce/plugins/instructure_rce_external_tools/components/util/ToolLaunchIframe.d.ts +4 -0
  43. package/es/rce/plugins/instructure_rce_external_tools/components/util/ToolLaunchIframe.js +4 -0
  44. package/es/rce/plugins/instructure_record/AudioOptionsTray/TrayController.d.ts +11 -2
  45. package/es/rce/plugins/instructure_record/AudioOptionsTray/TrayController.js +92 -10
  46. package/es/rce/plugins/instructure_record/AudioOptionsTray/index.d.ts +13 -1
  47. package/es/rce/plugins/instructure_record/AudioOptionsTray/index.js +216 -24
  48. package/es/rce/plugins/instructure_record/MediaPanel/index.js +16 -5
  49. package/es/rce/plugins/instructure_record/VideoOptionsTray/TrayController.d.ts +14 -13
  50. package/es/rce/plugins/instructure_record/VideoOptionsTray/TrayController.js +110 -39
  51. package/es/rce/plugins/instructure_record/VideoOptionsTray/index.d.ts +11 -1
  52. package/es/rce/plugins/instructure_record/VideoOptionsTray/index.js +242 -67
  53. package/es/rce/plugins/instructure_record/clickCallback.js +19 -4
  54. package/es/rce/plugins/instructure_record/mediaTranslations.js +1 -1
  55. package/es/rce/plugins/instructure_record/playerLayoutOptions.d.ts +25 -0
  56. package/es/rce/plugins/instructure_record/playerLayoutOptions.js +91 -0
  57. package/es/rce/plugins/instructure_record/plugin.js +2 -5
  58. package/es/rce/plugins/instructure_record/utils.d.ts +3 -0
  59. package/es/rce/plugins/instructure_record/utils.js +31 -0
  60. package/es/rce/plugins/instructure_studio_media_options/plugin.js +82 -26
  61. package/es/rce/plugins/shared/ContentSelection.d.ts +6 -1
  62. package/es/rce/plugins/shared/ContentSelection.js +15 -6
  63. package/es/rce/plugins/shared/DimensionsInput/DimensionInput.js +1 -2
  64. package/es/rce/plugins/shared/DimensionsInput/index.js +11 -12
  65. package/es/rce/plugins/shared/DimensionsInput/useDimensionsState.d.ts +1 -1
  66. package/es/rce/plugins/shared/DimensionsInput/useDimensionsState.js +4 -3
  67. package/es/rce/plugins/shared/StudioLtiSupportUtils.d.ts +27 -6
  68. package/es/rce/plugins/shared/StudioLtiSupportUtils.js +82 -13
  69. package/es/rce/plugins/shared/Upload/UploadFile.js +1 -8
  70. package/es/rce/style.d.ts +2 -1
  71. package/es/rce/style.js +4 -2
  72. package/es/rcs/api.d.ts +5 -10
  73. package/es/rcs/api.js +15 -21
  74. package/es/rcs/fake.d.ts +1 -7
  75. package/es/rcs/fake.js +1 -47
  76. package/es/sidebar/actions/media.d.ts +19 -6
  77. package/es/sidebar/actions/media.js +17 -4
  78. package/es/sidebar/actions/upload.d.ts +3 -3
  79. package/es/sidebar/actions/upload.js +9 -9
  80. package/es/sidebar/containers/Sidebar.js +0 -2
  81. package/es/sidebar/containers/sidebarHandlers.d.ts +2 -4
  82. package/es/sidebar/containers/sidebarHandlers.js +2 -5
  83. package/es/sidebar/reducers/index.d.ts +0 -1
  84. package/es/sidebar/reducers/index.js +0 -2
  85. package/es/sidebar/store/initialState.d.ts +0 -1
  86. package/es/sidebar/store/initialState.js +0 -5
  87. package/es/translations/locales/ar.js +65 -80
  88. package/es/translations/locales/ca.js +65 -80
  89. package/es/translations/locales/cy.js +65 -80
  90. package/es/translations/locales/da-x-k12.js +65 -80
  91. package/es/translations/locales/da.js +65 -80
  92. package/es/translations/locales/de.js +65 -80
  93. package/es/translations/locales/el.js +0 -9
  94. package/es/translations/locales/en-AU-x-unimelb.js +65 -80
  95. package/es/translations/locales/en-GB-x-ukhe.js +65 -80
  96. package/es/translations/locales/en.js +61 -79
  97. package/es/translations/locales/en_AU.js +65 -80
  98. package/es/translations/locales/en_CA.js +65 -80
  99. package/es/translations/locales/en_CY.js +65 -80
  100. package/es/translations/locales/en_GB.js +65 -80
  101. package/es/translations/locales/es.js +65 -80
  102. package/es/translations/locales/es_ES.js +65 -80
  103. package/es/translations/locales/fa_IR.js +0 -9
  104. package/es/translations/locales/fi.js +65 -80
  105. package/es/translations/locales/fr.js +65 -80
  106. package/es/translations/locales/fr_CA.js +65 -80
  107. package/es/translations/locales/ga.js +65 -80
  108. package/es/translations/locales/he.js +0 -9
  109. package/es/translations/locales/hi.js +65 -80
  110. package/es/translations/locales/ht.js +65 -80
  111. package/es/translations/locales/hu.js +0 -36
  112. package/es/translations/locales/hy.js +0 -9
  113. package/es/translations/locales/id.js +65 -80
  114. package/es/translations/locales/is.js +65 -80
  115. package/es/translations/locales/it.js +65 -80
  116. package/es/translations/locales/ja.js +65 -80
  117. package/es/translations/locales/ko.js +2455 -133
  118. package/es/translations/locales/mi.js +65 -80
  119. package/es/translations/locales/ms.js +65 -80
  120. package/es/translations/locales/nb-x-k12.js +65 -80
  121. package/es/translations/locales/nb.js +65 -80
  122. package/es/translations/locales/nl.js +66 -81
  123. package/es/translations/locales/nn.js +0 -36
  124. package/es/translations/locales/pl.js +65 -80
  125. package/es/translations/locales/pt.js +65 -80
  126. package/es/translations/locales/pt_BR.js +65 -80
  127. package/es/translations/locales/ru.js +65 -80
  128. package/es/translations/locales/sl.js +65 -80
  129. package/es/translations/locales/sv-x-k12.js +65 -80
  130. package/es/translations/locales/sv.js +65 -80
  131. package/es/translations/locales/th.js +65 -80
  132. package/es/translations/locales/tr.js +1962 -18
  133. package/es/translations/locales/uk_UA.js +0 -9
  134. package/es/translations/locales/vi.js +65 -80
  135. package/es/translations/locales/zh-Hans.js +65 -80
  136. package/es/translations/locales/zh-Hant.js +65 -80
  137. package/es/translations/locales/zh.js +65 -80
  138. package/es/translations/locales/zh_HK.js +65 -80
  139. package/eslint.config.js +16 -147
  140. package/jest/jest-setup.js +1 -0
  141. package/jest.config.js +2 -0
  142. package/oxlint.json +84 -0
  143. package/package.json +86 -62
  144. package/tsconfig.json +3 -2
  145. package/es/rce/plugins/shared/ai_tools/AIResponseModal.d.ts +0 -10
  146. package/es/rce/plugins/shared/ai_tools/AIResponseModal.js +0 -67
  147. package/es/rce/plugins/shared/ai_tools/AIToolsTray.d.ts +0 -18
  148. package/es/rce/plugins/shared/ai_tools/AIToolsTray.js +0 -489
  149. package/es/rce/plugins/shared/ai_tools/aiicons.d.ts +0 -7
  150. package/es/rce/plugins/shared/ai_tools/aiicons.js +0 -60
  151. package/es/rce/plugins/shared/ai_tools/index.d.ts +0 -3
  152. package/es/sidebar/actions/flickr.d.ts +0 -20
  153. package/es/sidebar/actions/flickr.js +0 -60
  154. package/es/sidebar/reducers/flickr.d.ts +0 -1
  155. package/es/sidebar/reducers/flickr.js +0 -49
@@ -18,37 +18,44 @@
18
18
 
19
19
  import React from 'react';
20
20
  import ReactDOM from 'react-dom';
21
+ import { AUDIO_PLAYER_SIZE as CANVAS_AUDIO_PLAYER_SIZE } from '@instructure/canvas-media';
21
22
  import bridge from '../../../../bridge';
23
+ import { showFlashAlert } from '../../../../common/FlashAlert';
24
+ import formatMessage from '../../../../format-message';
25
+ import RCEGlobals from '../../../RCEGlobals';
22
26
  import { asVideoElement } from '../../shared/ContentSelection';
23
27
  import { findMediaPlayerIframe } from '../../shared/iframeUtils';
28
+ import { isStudioEmbeddedMedia, parseStudioOptions, updateStudioEmbedOptions, validateStudioEmbedOptions } from '../../shared/StudioLtiSupportUtils';
24
29
  import VideoOptionsTray from '.';
25
- import { isStudioEmbeddedMedia, parseStudioOptions } from '../../shared/StudioLtiSupportUtils';
26
- import RCEGlobals from '../../../RCEGlobals';
27
30
  export const CONTAINER_ID = 'instructure-video-options-tray-container';
28
- export const VIDEO_SIZE_DEFAULT = {
29
- height: '225px',
30
- width: '400px'
31
- }; // AKA "LARGE"
32
31
  export const STUDIO_PLAYER_VIDEO_SIZE_DEFAULT = {
33
32
  height: '300px',
34
33
  width: '480px'
35
34
  };
36
35
  export const AUDIO_PLAYER_SIZE = {
37
- width: '320px',
38
- height: '14.25rem'
36
+ width: `${CANVAS_AUDIO_PLAYER_SIZE.width}px`,
37
+ height: `${CANVAS_AUDIO_PLAYER_SIZE.height}px`
39
38
  };
40
39
  export const videoDefaultSize = () => {
41
- if (RCEGlobals.getFeatures().consolidated_media_player) {
42
- return STUDIO_PLAYER_VIDEO_SIZE_DEFAULT;
43
- }
44
- return VIDEO_SIZE_DEFAULT;
40
+ return STUDIO_PLAYER_VIDEO_SIZE_DEFAULT;
45
41
  };
42
+ function onStudioEmbedOptionChanged(editor, videoContainer) {
43
+ return embedOptions => {
44
+ if (validateStudioEmbedOptions(embedOptions)) {
45
+ updateStudioEmbedOptions(editor, embedOptions, videoContainer);
46
+ }
47
+ };
48
+ }
46
49
  export default class TrayController {
47
50
  constructor() {
48
51
  this._editor = null;
49
52
  this._isOpen = false;
50
53
  this._shouldOpen = false;
51
54
  this._renderId = 0;
55
+ this._skipFocusOnExit = false;
56
+ this._captionsModified = false;
57
+ this.requestSubtitlesFromIframe = this.requestSubtitlesFromIframe.bind(this);
58
+ this.isStudioVideo = false;
52
59
  }
53
60
  get $container() {
54
61
  let $container = document.getElementById(CONTAINER_ID);
@@ -66,15 +73,28 @@ export default class TrayController {
66
73
  this._editor = editor;
67
74
  this.$videoContainer = findMediaPlayerIframe(editor.selection.getNode());
68
75
  this._shouldOpen = true;
76
+ this._captionsModified = false;
69
77
  if (bridge.focusedEditor) {
70
78
  // Dismiss any content trays that may already be open
71
- bridge.hideTrays();
79
+ bridge.hideTrays(); // Do we need to implement .hideTray functionality in this controller as well?
72
80
  }
73
- const trayProps = bridge.trayProps.get(editor);
74
- this._renderTray(trayProps);
81
+ this.isStudioVideo = isStudioEmbeddedMedia(this.$videoContainer);
82
+ // for studio embeds we don't need to show spinners
83
+ // so it is ready by default
84
+ this._isPlayerReady = this.isStudioVideo;
85
+
86
+ // Clean broadcast listeners for any existing trays which are not shown (if not cleaned automatically)
87
+ this._iframeLoadingListener?.abort();
88
+ if (!this.isStudioVideo) {
89
+ const videoOptions = asVideoElement(this.$videoContainer);
90
+ this._listenForPlayerIframeToLoad(videoOptions.id);
91
+ }
92
+ this._renderId++;
93
+ this._renderTray();
75
94
  }
76
- hideTrayForEditor(editor) {
95
+ hideTrayForEditor(editor, skipFocusOnExit = false) {
77
96
  if (this._editor === editor) {
97
+ this._skipFocusOnExit = skipFocusOnExit;
78
98
  this._dismissTray();
79
99
  }
80
100
  }
@@ -116,11 +136,14 @@ export default class TrayController {
116
136
  this._editor.selection.select(link);
117
137
  this.$videoContainer = null;
118
138
  }
139
+ const isCaptionImprovements = RCEGlobals.getFeatures()?.rce_asr_captioning_improvements || false;
119
140
  const data = {
120
141
  media_object_id: videoOptions.media_object_id,
121
142
  title: videoOptions.titleText,
143
+ attachment_id: videoOptions.attachment_id,
122
144
  subtitles: videoOptions.subtitles,
123
- attachment_id: videoOptions.attachment_id
145
+ skipCaptionUpdate: isCaptionImprovements,
146
+ viewerRestrictions: videoOptions.viewerRestrictions
124
147
  };
125
148
 
126
149
  // If the video just edited came from a file uploaded to canvas
@@ -130,11 +153,15 @@ export default class TrayController {
130
153
  if (hasMediaId && !videoOptions.editLocked) {
131
154
  videoOptions.updateMediaObject(data).then(_r => {
132
155
  if (this.$videoContainer && videoOptions.displayAs === 'embed') {
133
- this.$videoContainer.contentWindow.postMessage({
134
- subject: 'reload_media',
135
- media_object_id: videoOptions.media_object_id,
136
- attachment_id: data.attachment_id
137
- }, bridge.canvasOrigin);
156
+ if (isCaptionImprovements) {
157
+ this._reloadVideoPlayer();
158
+ } else {
159
+ this.$videoContainer.contentWindow.postMessage({
160
+ subject: 'reload_media',
161
+ media_object_id: videoOptions.media_object_id,
162
+ attachment_id: data.attachment_id
163
+ }, bridge.canvasOrigin);
164
+ }
138
165
  }
139
166
  }).catch(ex => {
140
167
  console.error('failed updating video captions', ex);
@@ -142,14 +169,55 @@ export default class TrayController {
142
169
  }
143
170
  }
144
171
  this._dismissTray();
172
+ setTimeout(() => {
173
+ showFlashAlert({
174
+ message: formatMessage('Media options saved.'),
175
+ type: 'success'
176
+ });
177
+ }, 0);
178
+ }
179
+ _listenForPlayerIframeToLoad(currentMediaId) {
180
+ if (!bridge.canvasOrigin) return;
181
+ this._iframeLoadingListener = new AbortController();
182
+
183
+ // Wait for player iframe to be loaded
184
+ window.addEventListener('message', event => {
185
+ // If tray was opened before player iframe was ready it will catch ready event.
186
+ // If not it will request it later and catch it here anyway.
187
+ if (event.data?.subject === 'media_player.iframe_ready' && event.data?.mediaId === currentMediaId) {
188
+ this._iframeLoadingListener.abort();
189
+ this._isPlayerReady = true;
190
+ this._renderTray();
191
+ }
192
+ }, {
193
+ signal: this._iframeLoadingListener.signal
194
+ });
195
+
196
+ // If tray was opened after player was loaded we need to request iframe_ready state
197
+ this.$videoContainer?.contentWindow?.postMessage({
198
+ subject: 'media_player.get_ready_state'
199
+ }, bridge.canvasOrigin);
200
+ }
201
+ _reloadVideoPlayer() {
202
+ if (this.$videoContainer?.contentWindow?.location) {
203
+ this.$videoContainer.contentWindow.location.reload();
204
+ }
145
205
  }
146
206
  _dismissTray() {
147
- if (this.$videoContainer) {
207
+ const isCaptionImprovements = RCEGlobals.getFeatures()?.rce_asr_captioning_improvements || false;
208
+
209
+ // Reload if captions were modified AND feature flag enabled
210
+ if (isCaptionImprovements && this._captionsModified && this.$videoContainer) {
211
+ this._reloadVideoPlayer();
212
+ }
213
+ if (this.$videoContainer && !this._skipFocusOnExit) {
148
214
  this._editor?.selection?.select(this.$videoContainer);
149
215
  }
150
216
  this._shouldOpen = false;
217
+ this._isOpen = false;
151
218
  this._renderTray();
152
219
  this._editor = null;
220
+ this._iframeLoadingListener?.abort();
153
221
  }
154
222
  requestSubtitlesFromIframe(cb) {
155
223
  if (!bridge.canvasOrigin) return;
@@ -165,37 +233,40 @@ export default class TrayController {
165
233
  subject: 'media_tracks_request'
166
234
  }, bridge.canvasOrigin);
167
235
  }
168
- _renderTray(trayProps) {
169
- let vo = {};
170
- if (this._shouldOpen) {
171
- /*
172
- * When the tray is being opened again, it should be rendered fresh
173
- * (clearing the internal state) so that the currently-selected video can
174
- * be used for initial video options.
175
- */
176
- this._renderId++;
177
- vo = asVideoElement(this.$videoContainer) || {};
178
- }
236
+ _renderTray() {
237
+ const vo = asVideoElement(this.$videoContainer, this.isStudioVideo) || {};
179
238
  const element = /*#__PURE__*/React.createElement(VideoOptionsTray, {
180
239
  id: "video-options-tray",
181
240
  key: this._renderId,
182
241
  videoOptions: vo,
183
242
  onEntered: () => {
184
243
  this._isOpen = true;
185
- },
244
+ }
245
+ // is not guaranteed to be called in case of showing another tray
246
+ ,
186
247
  onExited: () => {
187
- bridge.focusActiveEditor(false);
248
+ if (!this._skipFocusOnExit) {
249
+ bridge.focusActiveEditor(false);
250
+ }
251
+ this._skipFocusOnExit = false;
188
252
  this._isOpen = false;
189
253
  this._subtitleListener?.abort();
254
+ this._iframeLoadingListener?.abort();
255
+ this._isPlayerReady = false;
190
256
  },
191
257
  onSave: videoOptions => {
192
258
  this._applyVideoOptions(videoOptions);
193
259
  },
194
260
  onRequestClose: () => this._dismissTray(),
261
+ onCaptionsModified: () => {
262
+ this._captionsModified = true;
263
+ },
195
264
  open: this._shouldOpen,
196
- trayProps: trayProps,
197
- studioOptions: isStudioEmbeddedMedia(this.$videoContainer) ? parseStudioOptions(this.$videoContainer) : null,
198
- requestSubtitlesFromIframe: cb => this.requestSubtitlesFromIframe(cb)
265
+ trayProps: bridge.trayProps.get(this._editor),
266
+ studioOptions: this.isStudioVideo ? parseStudioOptions(this.$videoContainer) : null,
267
+ requestSubtitlesFromIframe: this.requestSubtitlesFromIframe,
268
+ onStudioEmbedOptionChanged: onStudioEmbedOptionChanged(this._editor, this.$videoContainer),
269
+ isLoading: !this._isPlayerReady
199
270
  });
200
271
  ReactDOM.render(element, this.$container);
201
272
  }
@@ -1,4 +1,4 @@
1
- declare function VideoOptionsTray({ videoOptions, onRequestClose, onSave, open, trayProps, requestSubtitlesFromIframe, onEntered, onExited, id, studioOptions, forBlockEditorUse, }: {
1
+ declare function VideoOptionsTray({ videoOptions, onRequestClose, onSave, open, trayProps, requestSubtitlesFromIframe, onEntered, onExited, id, studioOptions, forBlockEditorUse, onStudioEmbedOptionChanged, onCaptionsModified, isLoading, }: {
2
2
  videoOptions: any;
3
3
  onRequestClose: any;
4
4
  onSave: any;
@@ -10,6 +10,9 @@ declare function VideoOptionsTray({ videoOptions, onRequestClose, onSave, open,
10
10
  id?: string | undefined;
11
11
  studioOptions?: null | undefined;
12
12
  forBlockEditorUse?: boolean | undefined;
13
+ onStudioEmbedOptionChanged?: (() => void) | undefined;
14
+ onCaptionsModified?: null | undefined;
15
+ isLoading?: boolean | undefined;
13
16
  }): React.JSX.Element;
14
17
  declare namespace VideoOptionsTray {
15
18
  namespace propTypes {
@@ -23,6 +26,9 @@ declare namespace VideoOptionsTray {
23
26
  locale: import("prop-types").Validator<string>;
24
27
  inherited: import("prop-types").Requireable<boolean>;
25
28
  }> | null | undefined)[]>;
29
+ viewerRestrictions: import("prop-types").Requireable<import("prop-types").InferProps<{
30
+ show_rolling_transcript: import("prop-types").Requireable<boolean>;
31
+ }>>;
26
32
  }>>>;
27
33
  export { func as onEntered };
28
34
  export { func as onExited };
@@ -36,6 +42,9 @@ declare namespace VideoOptionsTray {
36
42
  export { string as id };
37
43
  export { parsedStudioOptionsPropType as studioOptions };
38
44
  export { func as requestSubtitlesFromIframe };
45
+ export { func as onStudioEmbedOptionChanged };
46
+ export { func as onCaptionsModified };
47
+ export { bool as isLoading };
39
48
  }
40
49
  }
41
50
  export default VideoOptionsTray;
@@ -43,3 +52,4 @@ import React from 'react';
43
52
  import { func } from 'prop-types';
44
53
  import { string } from 'prop-types';
45
54
  import { parsedStudioOptionsPropType } from '../../shared/StudioLtiSupportUtils';
55
+ import { bool } from 'prop-types';