@brightcove/components-embed-code-modal 1.0.8 → 1.1.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightcove/components-embed-code-modal",
3
- "version": "1.0.8",
3
+ "version": "1.1.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://bithub.brightcove.com/studio-ui-kit/studio-components-embed-code-modal.git"
@@ -1 +1 @@
1
- {"version":3,"file":"PrismPlayerPreview.d.ts","sourceRoot":"","sources":["../../../../../src/js/components/prism/PrismPlayerPreview.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAQ3C,UAAU,uBAAuB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,kBAAkB,kDAK5B,uBAAuB,sBA2EzB,CAAC"}
1
+ {"version":3,"file":"PrismPlayerPreview.d.ts","sourceRoot":"","sources":["../../../../../src/js/components/prism/PrismPlayerPreview.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAUjF,UAAU,uBAAuB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,kBAAkB,kDAK5B,uBAAuB,sBAmKzB,CAAC"}
@@ -56,7 +56,11 @@ export declare const resources: {
56
56
  };
57
57
  adConfiguration: string;
58
58
  prism: {
59
- getURL: string;
59
+ copying: string;
60
+ copied: string;
61
+ copyURL: string;
62
+ shortURL: string;
63
+ fullURL: string;
60
64
  customSettings: {
61
65
  sizing: string;
62
66
  };
@@ -119,7 +123,11 @@ export declare const resources: {
119
123
  };
120
124
  adConfiguration: string;
121
125
  prism: {
122
- getURL: string;
126
+ copying: string;
127
+ copied: string;
128
+ copyURL: string;
129
+ shortURL: string;
130
+ fullURL: string;
123
131
  customSettings: {
124
132
  sizing: string;
125
133
  };
@@ -182,7 +190,11 @@ export declare const resources: {
182
190
  unit: string;
183
191
  };
184
192
  prism: {
185
- getURL: string;
193
+ copying: string;
194
+ copied: string;
195
+ copyURL: string;
196
+ shortURL: string;
197
+ fullURL: string;
186
198
  customSettings: {
187
199
  sizing: string;
188
200
  };
@@ -245,7 +257,11 @@ export declare const resources: {
245
257
  unit: string;
246
258
  };
247
259
  prism: {
248
- getURL: string;
260
+ copying: string;
261
+ copied: string;
262
+ copyURL: string;
263
+ shortURL: string;
264
+ fullURL: string;
249
265
  customSettings: {
250
266
  sizing: string;
251
267
  };
@@ -308,7 +324,11 @@ export declare const resources: {
308
324
  unit: string;
309
325
  };
310
326
  prism: {
311
- getURL: string;
327
+ copying: string;
328
+ copied: string;
329
+ copyURL: string;
330
+ shortURL: string;
331
+ fullURL: string;
312
332
  customSettings: {
313
333
  sizing: string;
314
334
  };
@@ -371,7 +391,11 @@ export declare const resources: {
371
391
  unit: string;
372
392
  };
373
393
  prism: {
374
- getURL: string;
394
+ copying: string;
395
+ copied: string;
396
+ copyURL: string;
397
+ shortURL: string;
398
+ fullURL: string;
375
399
  customSettings: {
376
400
  sizing: string;
377
401
  };
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/js/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,SAAS,CAAC;AAU3B,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmBrB,CAAC;AAaF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/js/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,SAAS,CAAC;AAU3B,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmBrB,CAAC;AAaF,eAAe,IAAI,CAAC"}
@@ -46,6 +46,34 @@ jest.mock('react-i18next', () => ({
46
46
  Trans: () => '<div/>',
47
47
  }));
48
48
 
49
+ const evaluateMediaQuery = (query) => {
50
+ const minWidth = /min-width:\s*(\d+)px/.exec(query);
51
+ const maxWidth = /max-width:\s*(\d+)px/.exec(query);
52
+
53
+ if (minWidth && window.innerWidth < Number(minWidth[1])) {
54
+ return false;
55
+ }
56
+ if (maxWidth && window.innerWidth > Number(maxWidth[1])) {
57
+ return false;
58
+ }
59
+ return true;
60
+ };
61
+
62
+ const noop = () => {
63
+ return;
64
+ };
65
+
66
+ window.matchMedia = (query) => ({
67
+ matches: evaluateMediaQuery(query),
68
+ media: query,
69
+ onchange: null,
70
+ addEventListener: noop,
71
+ removeEventListener: noop,
72
+ addListener: noop,
73
+ removeListener: noop,
74
+ dispatchEvent: () => false,
75
+ });
76
+
49
77
  global.StudioModule = {
50
78
  config: {
51
79
  product: {
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@brightcove/components-embed-code-modal",
3
- "version": "1.0.8",
3
+ "version": "1.1.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://bithub.brightcove.com/studio-ui-kit/studio-components-embed-code-modal.git"
7
7
  },
8
8
  "description": "Embed Code Modal used for publishing videos",
9
9
  "main": "build/index.js",
10
- "types": "./src/index.d.ts",
10
+ "types": "./build/src/index.d.ts",
11
11
  "author": "Campaign Team",
12
12
  "scripts": {
13
13
  "demo": "NODE_ENV=development DEMO=1 webpack-dev-server --progress --color",
@@ -7,6 +7,7 @@ const BUILD_DIR = path.resolve(__dirname, '..', 'build');
7
7
  pkg.name = '@brightcove/components-embed-code-modal'
8
8
  pkg.main = './index.js';
9
9
  pkg.module = './index.js';
10
+ pkg.types = './src/index.d.ts';
10
11
 
11
12
  delete pkg.scripts.prepare;
12
13
  delete pkg.scripts['lint:staged'];
@@ -1,9 +1,11 @@
1
- import React, { useCallback } from 'react';
1
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import ReactPlayerLoader from '@brightcove/react-player-loader';
3
- import { PrismButton } from '@brightcove/prism-core';
3
+ import { PrismButton, PrismButtonDropdown } from '@brightcove/prism-core';
4
4
  import { getBrightcove, getUrlBase } from 'js/utils/util';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
+ import { getUrlAndAddItToClipboard } from '../VideoLinks';
8
+
7
9
  import css from 'styles/prism/PrismLiveModal.sass';
8
10
 
9
11
  interface PrismPlayerPreviewProps {
@@ -22,33 +24,119 @@ export const PrismPlayerPreview = ({
22
24
  previewUrl,
23
25
  }: PrismPlayerPreviewProps) => {
24
26
  const { t } = useTranslation();
27
+ const [isShorteningUrl, setIsShorteningUrl] = useState<boolean>(false);
28
+ const [isCopied, setIsCopied] = useState<boolean>(false);
29
+ const copiedTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
30
+ const shortenRequestRef = useRef<number>(0);
31
+
32
+ useEffect(
33
+ () => () => {
34
+ shortenRequestRef.current += 1;
35
+ if (copiedTimeoutRef.current) {
36
+ clearTimeout(copiedTimeoutRef.current);
37
+ }
38
+ setIsShorteningUrl(false);
39
+ setIsCopied(false);
40
+ },
41
+ [previewUrl],
42
+ );
43
+
44
+ const notifyMissingPreviewUrl = useCallback(() => {
45
+ getBrightcove().Toaster.error({
46
+ title: t('toasterTitle') as string,
47
+ message: 'Please select a player first',
48
+ });
49
+ }, [t]);
50
+
51
+ const showCopiedFeedback = useCallback(() => {
52
+ if (copiedTimeoutRef.current) {
53
+ clearTimeout(copiedTimeoutRef.current);
54
+ }
55
+ setIsCopied(true);
56
+ copiedTimeoutRef.current = setTimeout(() => setIsCopied(false), 2000);
57
+ }, []);
25
58
 
26
- const handleCopyUrl = useCallback(() => {
59
+ const handleCopyFullUrl = useCallback(() => {
27
60
  if (!previewUrl) {
28
- getBrightcove().Toaster.error({
29
- title: t('toasterTitle') as string,
30
- message: 'Please select a player first',
61
+ notifyMissingPreviewUrl();
62
+ return;
63
+ }
64
+ navigator.clipboard
65
+ .writeText(previewUrl)
66
+ .then(showCopiedFeedback)
67
+ .catch(() => {
68
+ getBrightcove().Toaster.error({
69
+ message: t('toasterErrorMessage') as string,
70
+ });
31
71
  });
72
+ }, [previewUrl, t, notifyMissingPreviewUrl, showCopiedFeedback]);
73
+
74
+ const handleCopyShortUrl = useCallback(() => {
75
+ if (!previewUrl) {
76
+ notifyMissingPreviewUrl();
32
77
  return;
33
78
  }
34
- navigator.clipboard.writeText(previewUrl).then(() => {
35
- getBrightcove().Toaster.success({
36
- title: t('toasterTitle') as string,
37
- message: t('toasterGetURLSuccess') as string,
79
+ const requestId = shortenRequestRef.current + 1;
80
+ shortenRequestRef.current = requestId;
81
+ const isCurrentRequest = () => shortenRequestRef.current === requestId;
82
+
83
+ setIsShorteningUrl(true);
84
+ getUrlAndAddItToClipboard(previewUrl)
85
+ .then(() => {
86
+ if (isCurrentRequest()) {
87
+ showCopiedFeedback();
88
+ }
89
+ })
90
+ .catch(() => {
91
+ if (isCurrentRequest()) {
92
+ getBrightcove().Toaster.error({
93
+ message: t('toasterGetURLError') as string,
94
+ });
95
+ }
96
+ })
97
+ .finally(() => {
98
+ if (isCurrentRequest()) {
99
+ setIsShorteningUrl(false);
100
+ }
38
101
  });
39
- });
40
- }, [previewUrl, t]);
102
+ }, [previewUrl, t, notifyMissingPreviewUrl, showCopiedFeedback]);
103
+
104
+ const copyUrlOptions = useMemo(
105
+ () => [
106
+ {
107
+ id: 'short-url',
108
+ label: t('prism.shortURL') as string,
109
+ icon: 'LAYERS_SUBTRACT',
110
+ onClick: handleCopyShortUrl,
111
+ disabled: isShorteningUrl,
112
+ },
113
+ {
114
+ id: 'full-url',
115
+ label: t('prism.fullURL') as string,
116
+ icon: 'LAYERS_SUBTRACT',
117
+ onClick: handleCopyFullUrl,
118
+ },
119
+ ],
120
+ [t, handleCopyShortUrl, handleCopyFullUrl, isShorteningUrl],
121
+ );
122
+
123
+ const copyUrlLabel = () => {
124
+ if (isCopied) {
125
+ return t('prism.copied') as string;
126
+ }
127
+ if (isShorteningUrl) {
128
+ return t('prism.copying') as string;
129
+ }
130
+ return t('prism.copyURL') as string;
131
+ };
41
132
 
42
133
  const handleOpenPreview = useCallback(() => {
43
134
  if (!previewUrl) {
44
- getBrightcove().Toaster.error({
45
- title: t('toasterTitle') as string,
46
- message: 'Please select a player first',
47
- });
135
+ notifyMissingPreviewUrl();
48
136
  return;
49
137
  }
50
138
  window.open(previewUrl, '_blank', 'noopener,noreferrer');
51
- }, [previewUrl, t]);
139
+ }, [previewUrl, notifyMissingPreviewUrl]);
52
140
 
53
141
  // Build player options for Live modal
54
142
  // Note: Following Bluesteel pattern - we DON'T pass adConfigId or livePlaybackToken
@@ -63,15 +151,17 @@ export const PrismPlayerPreview = ({
63
151
  return (
64
152
  <div className={css.prismPlayerPreviewContainer}>
65
153
  <div className={css.prismPlayerActions}>
66
- <PrismButton
154
+ <PrismButtonDropdown
67
155
  variant='Primary'
68
156
  size='small'
69
- onClick={handleCopyUrl}
70
- rightIcon='copy'
71
- disabled={!previewUrl}
157
+ options={copyUrlOptions}
158
+ modalTitle={t('prism.copyURL') as string}
159
+ showDropdownIcon={!isCopied && !isShorteningUrl}
160
+ {...(isCopied ? { rightIcon: 'CHECK' } : {})}
161
+ disabled={!previewUrl || isShorteningUrl || isCopied}
72
162
  >
73
- {t('prism.getURL') as string}
74
- </PrismButton>
163
+ {copyUrlLabel()}
164
+ </PrismButtonDropdown>
75
165
  <PrismButton
76
166
  variant='Primary'
77
167
  size='small'
@@ -53,7 +53,11 @@
53
53
  },
54
54
  "adConfiguration": "Ad Configuration",
55
55
  "prism": {
56
- "getURL": "URL",
56
+ "copying": "Copying...",
57
+ "copied": "Copied",
58
+ "copyURL": "Copy URL",
59
+ "shortURL": "Short URL",
60
+ "fullURL": "Full URL",
57
61
  "customSettings": {
58
62
  "sizing": "Player Sizing"
59
63
  }
@@ -53,7 +53,11 @@
53
53
  },
54
54
  "adConfiguration": "Configuración de Anuncios",
55
55
  "prism": {
56
- "getURL": "URL",
56
+ "copying": "Copiando...",
57
+ "copied": "Copiado",
58
+ "copyURL": "Copiar URL",
59
+ "shortURL": "URL corta",
60
+ "fullURL": "URL completa",
57
61
  "customSettings": {
58
62
  "sizing": "Tamaño del Reproductor"
59
63
  }
@@ -53,7 +53,11 @@
53
53
  "unit": "s"
54
54
  },
55
55
  "prism": {
56
- "getURL": "URL",
56
+ "copying": "Copie en cours...",
57
+ "copied": "Copié",
58
+ "copyURL": "Copier l'URL",
59
+ "shortURL": "URL courte",
60
+ "fullURL": "URL complète",
57
61
  "customSettings": {
58
62
  "sizing": "Taille du Lecteur"
59
63
  }
@@ -53,7 +53,11 @@
53
53
  "unit": "秒"
54
54
  },
55
55
  "prism": {
56
- "getURL": "URL",
56
+ "copying": "コピー中...",
57
+ "copied": "コピー済み",
58
+ "copyURL": "URLをコピー",
59
+ "shortURL": "短縮URL",
60
+ "fullURL": "完全なURL",
57
61
  "customSettings": {
58
62
  "sizing": "プレーヤーのサイズ"
59
63
  }
@@ -53,7 +53,11 @@
53
53
  "unit": "초"
54
54
  },
55
55
  "prism": {
56
- "getURL": "URL",
56
+ "copying": "복사 중...",
57
+ "copied": "복사됨",
58
+ "copyURL": "URL 복사",
59
+ "shortURL": "짧은 URL",
60
+ "fullURL": "전체 URL",
57
61
  "customSettings": {
58
62
  "sizing": "플레이어 크기"
59
63
  }
@@ -53,7 +53,11 @@
53
53
  "unit": "秒"
54
54
  },
55
55
  "prism": {
56
- "getURL": "URL",
56
+ "copying": "複製中...",
57
+ "copied": "已複製",
58
+ "copyURL": "複製URL",
59
+ "shortURL": "短網址",
60
+ "fullURL": "完整URL",
57
61
  "customSettings": {
58
62
  "sizing": "播放程式大小"
59
63
  }