@smartimpact-it/modern-video-embed 2.0.4 → 2.0.6

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 (65) hide show
  1. package/README.md +322 -71
  2. package/dist/components/BaseVideoEmbed.d.ts +86 -0
  3. package/dist/components/BaseVideoEmbed.d.ts.map +1 -0
  4. package/dist/components/BaseVideoEmbed.js +256 -0
  5. package/dist/components/BaseVideoEmbed.js.map +1 -0
  6. package/dist/components/VideoEmbed.d.ts +68 -0
  7. package/dist/components/VideoEmbed.d.ts.map +1 -0
  8. package/dist/components/VideoEmbed.js +770 -0
  9. package/dist/components/VideoEmbed.js.map +1 -0
  10. package/dist/components/VimeoEmbed.d.ts +26 -36
  11. package/dist/components/VimeoEmbed.d.ts.map +1 -1
  12. package/dist/components/VimeoEmbed.js +205 -328
  13. package/dist/components/VimeoEmbed.js.map +1 -1
  14. package/dist/components/VimeoEmbed.min.js +1 -1
  15. package/dist/components/YouTubeEmbed.d.ts +108 -42
  16. package/dist/components/YouTubeEmbed.d.ts.map +1 -1
  17. package/dist/components/YouTubeEmbed.js +341 -373
  18. package/dist/components/YouTubeEmbed.js.map +1 -1
  19. package/dist/components/YouTubeEmbed.min.js +1 -1
  20. package/dist/css/components.css +235 -44
  21. package/dist/css/components.css.map +1 -1
  22. package/dist/css/components.min.css +1 -1
  23. package/dist/css/main.css +235 -44
  24. package/dist/css/main.css.map +1 -1
  25. package/dist/css/main.min.css +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.min.js +1 -1
  31. package/dist/types/index.d.ts +1 -0
  32. package/dist/types/index.d.ts.map +1 -1
  33. package/dist/video-only.d.ts +7 -0
  34. package/dist/video-only.d.ts.map +1 -0
  35. package/dist/video-only.js +8 -0
  36. package/dist/video-only.js.map +1 -0
  37. package/dist/vimeo-only.d.ts +2 -2
  38. package/dist/vimeo-only.d.ts.map +1 -1
  39. package/dist/vimeo-only.js +2 -2
  40. package/dist/vimeo-only.js.map +1 -1
  41. package/dist/vimeo-only.min.js +1 -1
  42. package/dist/youtube-only.d.ts +2 -2
  43. package/dist/youtube-only.d.ts.map +1 -1
  44. package/dist/youtube-only.js +2 -2
  45. package/dist/youtube-only.js.map +1 -1
  46. package/dist/youtube-only.min.js +1 -1
  47. package/package.json +6 -5
  48. package/src/components/BaseVideoEmbed.ts +303 -0
  49. package/src/components/VideoEmbed.ts +852 -0
  50. package/src/components/VideoEmbed.ts.backup +1051 -0
  51. package/src/components/VimeoEmbed.ts +233 -397
  52. package/src/components/YouTubeEmbed.ts +359 -430
  53. package/src/index.ts +1 -0
  54. package/src/styles/_embed-base.scss +255 -0
  55. package/src/styles/_shared-functions.scss +56 -0
  56. package/src/styles/components.scss +4 -3
  57. package/src/styles/main.scss +7 -5
  58. package/src/styles/video-embed.scss +37 -0
  59. package/src/styles/vimeo-embed.scss +8 -248
  60. package/src/styles/youtube-embed.scss +8 -254
  61. package/src/types/index.ts +1 -0
  62. package/src/types/video-embed.d.ts +90 -0
  63. package/src/video-only.ts +9 -0
  64. package/src/vimeo-only.ts +2 -2
  65. package/src/youtube-only.ts +2 -2
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  // Main entry point for Video Embed Components
2
2
  import "./components/YouTubeEmbed.js";
3
3
  import "./components/VimeoEmbed.js";
4
+ import "./components/VideoEmbed.js";
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Base styles and mixins for all video embed components
3
+ * Provides reusable CSS patterns to reduce duplication
4
+ */
5
+
6
+ @use "shared-functions" as *;
7
+
8
+ // CSS Variables (common across all components)
9
+ @mixin embed-css-variables {
10
+ --video-aspect-ratio: 56.25%; // Default 16:9
11
+ --poster-object-fit: cover;
12
+ --video-object-fit: contain;
13
+ --control-button-size: 70px;
14
+ --control-button-color: #ffffff;
15
+ --overlay-background-color: rgba(0, 0, 0, 0.5);
16
+ }
17
+
18
+ // Base container styles
19
+ @mixin embed-container-base {
20
+ display: block;
21
+ position: relative;
22
+ width: 100%;
23
+ padding-top: var(--video-aspect-ratio);
24
+ overflow: hidden;
25
+ background-color: #000;
26
+ }
27
+
28
+ // Media element positioning (iframe or video)
29
+ @mixin embed-media-base {
30
+ position: absolute;
31
+ top: 0;
32
+ left: 0;
33
+ width: 100%;
34
+ height: 100%;
35
+ border: none;
36
+ object-fit: var(--video-object-fit);
37
+ }
38
+
39
+ // Poster image styles
40
+ @mixin embed-poster {
41
+ .video-poster,
42
+ .youtube-poster,
43
+ .vimeo-poster {
44
+ position: absolute;
45
+ top: 0;
46
+ left: 0;
47
+ width: 100%;
48
+ height: 100%;
49
+ object-fit: var(--poster-object-fit);
50
+ display: block;
51
+ cursor: pointer;
52
+ }
53
+ }
54
+
55
+ // Custom control button overlay
56
+ @mixin embed-button-overlay {
57
+ .button-overlay {
58
+ background: var(--overlay-background-color);
59
+ cursor: pointer;
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ position: absolute;
64
+ left: 0;
65
+ top: 0;
66
+ right: 0;
67
+ bottom: 0;
68
+ height: 100%;
69
+ width: 100%;
70
+ transition: opacity 0.3s ease;
71
+ z-index: 10;
72
+ }
73
+
74
+ &.is-playing .button-overlay {
75
+ opacity: 0;
76
+ pointer-events: none;
77
+ }
78
+
79
+ &.is-playing:hover .button-overlay {
80
+ opacity: 1;
81
+ pointer-events: auto;
82
+ }
83
+
84
+ .button-overlay .button {
85
+ cursor: pointer;
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ height: var(--control-button-size);
90
+ width: var(--control-button-size);
91
+ background-image: inline-svg(
92
+ '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="#ffffff" d="M8,5.14V19.14L19,12.14L8,5.14Z" /></svg>'
93
+ );
94
+ background-size: cover;
95
+ background-repeat: no-repeat;
96
+ background-position: center;
97
+ }
98
+
99
+ &.is-playing .button-overlay .button {
100
+ background-image: inline-svg(
101
+ '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="#ffffff" d="M14,19H18V5H14M6,19H10V5H6V19Z" /></svg>'
102
+ );
103
+ }
104
+ }
105
+
106
+ // Background mode styles (for background video effect)
107
+ @mixin embed-background-mode($media-type: "iframe") {
108
+ &.is-background {
109
+ padding-top: 0;
110
+ position: absolute;
111
+ height: 100%;
112
+ width: 100%;
113
+ top: 0;
114
+ left: 0;
115
+ z-index: 0;
116
+ overflow: hidden;
117
+ background: #000;
118
+
119
+ @if $media-type == "iframe" {
120
+ iframe {
121
+ position: absolute;
122
+ top: 50%;
123
+ left: 50%;
124
+ transform: translate(-50%, -50%);
125
+ aspect-ratio: 16 / 9;
126
+ width: auto;
127
+ height: auto;
128
+ min-width: 100%;
129
+ min-height: 100%;
130
+ pointer-events: none;
131
+ }
132
+ } @else if $media-type == "video" {
133
+ video {
134
+ position: absolute;
135
+ top: 50%;
136
+ left: 50%;
137
+ transform: translate(-50%, -50%);
138
+ width: 100%;
139
+ height: 100%;
140
+ object-fit: cover;
141
+ pointer-events: none;
142
+ }
143
+ }
144
+
145
+ .button-overlay {
146
+ display: none;
147
+ }
148
+ }
149
+
150
+ // When background controls are enabled
151
+ &.has-background-controls {
152
+ .button-overlay {
153
+ display: flex;
154
+ background: none;
155
+ justify-content: flex-end;
156
+ align-items: flex-end;
157
+ padding: 1rem;
158
+
159
+ .button {
160
+ --control-button-size: 40px;
161
+ opacity: 0.7;
162
+ transition: opacity 0.2s ease;
163
+ &:hover {
164
+ opacity: 1;
165
+ }
166
+ }
167
+ }
168
+
169
+ &.is-playing .button-overlay {
170
+ opacity: 0;
171
+ &:hover {
172
+ opacity: 1;
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ // Error message display
179
+ @mixin embed-error-message(
180
+ $error-class,
181
+ $accent-color: #ff4444,
182
+ $hover-color: #cc0000
183
+ ) {
184
+ .#{$error-class} {
185
+ position: absolute;
186
+ top: 0;
187
+ left: 0;
188
+ width: 100%;
189
+ height: 100%;
190
+ display: flex;
191
+ align-items: center;
192
+ justify-content: center;
193
+ background: rgba(0, 0, 0, 0.9);
194
+ color: white;
195
+ z-index: 1000;
196
+
197
+ .error-content {
198
+ text-align: center;
199
+ padding: 2rem;
200
+ max-width: 400px;
201
+
202
+ svg {
203
+ color: $accent-color;
204
+ margin-bottom: 1rem;
205
+ }
206
+
207
+ .error-message {
208
+ margin: 1rem 0;
209
+ font-size: 1rem;
210
+ line-height: 1.5;
211
+ }
212
+
213
+ .retry-button {
214
+ margin-top: 1rem;
215
+ padding: 0.75rem 1.5rem;
216
+ background: $accent-color;
217
+ color: white;
218
+ border: none;
219
+ border-radius: 4px;
220
+ cursor: pointer;
221
+ font-size: 1rem;
222
+ font-weight: 600;
223
+ transition: background 0.2s ease;
224
+
225
+ &:hover {
226
+ background: $hover-color;
227
+ }
228
+
229
+ &:focus {
230
+ outline: 2px solid white;
231
+ outline-offset: 2px;
232
+ }
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ // Complete base mixin that includes all common styles
239
+ @mixin embed-base-styles(
240
+ $component-name,
241
+ $media-type: "iframe",
242
+ $accent-color: #ff4444,
243
+ $hover-color: #cc0000
244
+ ) {
245
+ @include embed-css-variables;
246
+ @include embed-container-base;
247
+ @include embed-poster;
248
+ @include embed-button-overlay;
249
+ @include embed-background-mode($media-type);
250
+ @include embed-error-message(
251
+ "#{$component-name}-error-message",
252
+ $accent-color,
253
+ $hover-color
254
+ );
255
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Shared SCSS functions for SVG encoding
3
+ * Used by all video embed components
4
+ */
5
+
6
+ // No imports needed - this is a base module
7
+
8
+ @function svg-str-replace($string, $search, $replace: "") {
9
+ $index: str-index($string, $search);
10
+ @if $index {
11
+ @return str-slice($string, 1, $index - 1) + $replace +
12
+ svg-str-replace(
13
+ str-slice($string, $index + str-length($search)),
14
+ $search,
15
+ $replace
16
+ );
17
+ }
18
+ @return $string;
19
+ }
20
+
21
+ @function svg-url-encode($string) {
22
+ $map: (
23
+ "%": "%25",
24
+ "<": "%3C",
25
+ ">": "%3E",
26
+ " ": "%20",
27
+ "!": "%21",
28
+ "*": "%2A",
29
+ "'": "%27",
30
+ '"': "%22",
31
+ "(": "%28",
32
+ ")": "%29",
33
+ ";": "%3B",
34
+ ":": "%3A",
35
+ "@": "%40",
36
+ "&": "%26",
37
+ "=": "%3D",
38
+ "+": "%2B",
39
+ "$": "%24",
40
+ ",": "%2C",
41
+ "/": "%2F",
42
+ "?": "%3F",
43
+ "#": "%23",
44
+ "[": "%5B",
45
+ "]": "%5D",
46
+ );
47
+ $new: $string;
48
+ @each $search, $replace in $map {
49
+ $new: #{svg-str-replace($new, $search, $replace)};
50
+ }
51
+ @return $new;
52
+ }
53
+
54
+ @function inline-svg($string) {
55
+ @return url("data:image/svg+xml;utf8,#{svg-url-encode($string)}");
56
+ }
@@ -2,6 +2,7 @@
2
2
  // This file contains only the essential styles needed for the video embed components
3
3
  // Use this when integrating into your website
4
4
 
5
- // Import our custom video embed styles
6
- @import "./youtube-embed.scss";
7
- @import "./vimeo-embed.scss";
5
+ // Use our custom video embed styles
6
+ @use "./youtube-embed.scss";
7
+ @use "./vimeo-embed.scss";
8
+ @use "./video-embed.scss";
@@ -2,9 +2,11 @@
2
2
  // This file includes Bootstrap and component styles for demos and examples
3
3
  // For production integration, use components.scss instead
4
4
 
5
- // Import Bootstrap SCSS (only needed for demos)
6
- @import "../../node_modules/bootstrap/scss/bootstrap";
5
+ // Use Bootstrap SCSS (only needed for demos)
6
+ // Using 'as *' to maintain global namespace compatibility
7
+ @use "../../node_modules/bootstrap/scss/bootstrap" as *;
7
8
 
8
- // Import our custom video embed styles
9
- @import "./youtube-embed.scss";
10
- @import "./vimeo-embed.scss";
9
+ // Use our custom video embed styles
10
+ @use "./youtube-embed.scss";
11
+ @use "./vimeo-embed.scss";
12
+ @use "./video-embed.scss";
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Video Embed Component Styles
3
+ * Uses shared base styles with video-specific overrides
4
+ */
5
+ @use "embed-base" as *;
6
+
7
+ video-embed {
8
+ // Import all common embed styles
9
+ @include embed-base-styles("video", "video", #ff4444, #cc0000);
10
+
11
+ // Video-specific styles only
12
+ video {
13
+ @include embed-media-base;
14
+ }
15
+
16
+ // Poster image specific to video (uses background-image pattern)
17
+ .video-poster {
18
+ background-size: cover;
19
+ background-position: center;
20
+ background-repeat: no-repeat;
21
+ }
22
+
23
+ // Fullscreen mode (video-specific)
24
+ &.is-fullscreen {
25
+ padding-top: 0;
26
+ position: fixed;
27
+ top: 0;
28
+ left: 0;
29
+ width: 100vw;
30
+ height: 100vh;
31
+ z-index: 9999;
32
+
33
+ video {
34
+ object-fit: contain;
35
+ }
36
+ }
37
+ }
@@ -1,255 +1,15 @@
1
1
  /**
2
- * SVG encoding functions (shared with YouTube embed)
3
- */
4
- @function svg-str-replace($string, $search, $replace: "") {
5
- $index: str-index($string, $search);
6
- @if $index {
7
- @return str-slice($string, 1, $index - 1) + $replace +
8
- svg-str-replace(
9
- str-slice($string, $index + str-length($search)),
10
- $search,
11
- $replace
12
- );
13
- }
14
- @return $string;
15
- }
16
-
17
- @function svg-url-encode($string) {
18
- $map: (
19
- "%": "%25",
20
- "<": "%3C",
21
- ">": "%3E",
22
- " ": "%20",
23
- "!": "%21",
24
- "*": "%2A",
25
- "'": "%27",
26
- '"': "%22",
27
- "(": "%28",
28
- ")": "%29",
29
- ";": "%3B",
30
- ":": "%3A",
31
- "@": "%40",
32
- "&": "%26",
33
- "=": "%3D",
34
- "+": "%2B",
35
- "$": "%24",
36
- ",": "%2C",
37
- "/": "%2F",
38
- "?": "%3F",
39
- "#": "%23",
40
- "[": "%5B",
41
- "]": "%5D",
42
- );
43
- $new: $string;
44
- @each $search, $replace in $map {
45
- $new: #{svg-str-replace($new, $search, $replace)};
46
- }
47
- @return $new;
48
- }
49
-
50
- @function inline-svg($string) {
51
- @return url("data:image/svg+xml;utf8,#{svg-url-encode($string)}");
52
- }
2
+ * Vimeo Embed Component Styles
3
+ * Uses shared base styles with Vimeo-specific branding
4
+ */
5
+ @use "embed-base" as *;
53
6
 
54
7
  vimeo-embed {
55
- // CSS Variables for customization
56
- --video-aspect-ratio: 56.25%; // Default 16:9
57
- --poster-object-fit: cover;
58
- --video-object-fit: contain;
59
- --control-button-size: 70px;
60
- --control-button-color: #ffffff;
61
- --overlay-background-color: rgba(0, 0, 0, 0.5);
62
-
63
- display: block;
64
- position: relative;
65
- width: 100%;
66
- padding-top: var(--video-aspect-ratio);
67
- overflow: hidden;
68
- background-color: #000;
8
+ // Import all common embed styles with Vimeo blue accent
9
+ @include embed-base-styles("vimeo", "iframe", #00adef, #0088bf);
69
10
 
11
+ // iframe-specific styles
70
12
  iframe {
71
- position: absolute;
72
- top: 0;
73
- left: 0;
74
- width: 100%;
75
- height: 100%;
76
- border: none;
77
- object-fit: var(--video-object-fit);
78
- }
79
-
80
- // Poster image
81
- .vimeo-poster,
82
- .video-poster {
83
- position: absolute;
84
- top: 0;
85
- left: 0;
86
- width: 100%;
87
- height: 100%;
88
- object-fit: var(--poster-object-fit);
89
- display: block;
90
- cursor: pointer;
91
- }
92
-
93
- // Custom control overlay
94
- .button-overlay {
95
- background: var(--overlay-background-color);
96
- cursor: pointer;
97
- display: flex;
98
- align-items: center;
99
- justify-content: center;
100
- position: absolute;
101
- left: 0;
102
- top: 0;
103
- right: 0;
104
- bottom: 0;
105
- height: 100%;
106
- width: 100%;
107
- transition: opacity 0.3s ease;
108
- z-index: 10;
109
- }
110
-
111
- &.is-playing .button-overlay {
112
- opacity: 0;
113
- }
114
-
115
- &.is-playing:hover .button-overlay {
116
- opacity: 1;
117
- }
118
-
119
- .button-overlay .button {
120
- cursor: pointer;
121
- display: flex;
122
- align-items: center;
123
- justify-content: center;
124
- height: var(--control-button-size);
125
- width: var(--control-button-size);
126
- background-image: inline-svg(
127
- '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="#ffffff" d="M8,5.14V19.14L19,12.14L8,5.14Z" /></svg>'
128
- );
129
- background-size: cover;
130
- background-repeat: no-repeat;
131
- background-position: center;
132
- }
133
-
134
- &.is-playing .button-overlay .button {
135
- background-image: inline-svg(
136
- '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="#ffffff" d="M14,19H18V5H14M6,19H10V5H6V19Z" /></svg>'
137
- );
138
- }
139
-
140
- // Background mode styles
141
- &.is-background {
142
- padding-top: 0;
143
- position: absolute;
144
- height: 100%;
145
- width: 100%;
146
- top: 0;
147
- left: 0;
148
- z-index: 0;
149
- overflow: hidden;
150
- background: #000;
151
-
152
- iframe {
153
- position: absolute;
154
- top: 50%;
155
- left: 50%;
156
- transform: translate(-50%, -50%);
157
-
158
- min-width: 100%;
159
- min-height: 100%;
160
- width: auto;
161
- height: auto;
162
-
163
- @supports (aspect-ratio: 16 / 9) {
164
- aspect-ratio: 16 / 9;
165
- }
166
-
167
- pointer-events: none;
168
- }
169
-
170
- .button-overlay {
171
- display: none;
172
- }
173
- }
174
-
175
- // When background controls are enabled
176
- &.has-background-controls {
177
- .button-overlay {
178
- display: flex;
179
- background: none;
180
- justify-content: flex-end;
181
- align-items: flex-end;
182
- padding: 1rem;
183
-
184
- .button {
185
- --control-button-size: 40px;
186
- opacity: 0.7;
187
- transition: opacity 0.2s ease;
188
- &:hover {
189
- opacity: 1;
190
- }
191
- }
192
- }
193
-
194
- &.is-playing .button-overlay {
195
- opacity: 0;
196
- &:hover {
197
- opacity: 1;
198
- }
199
- }
200
- }
201
-
202
- // Error message styling
203
- .vimeo-error-message {
204
- position: absolute;
205
- top: 0;
206
- left: 0;
207
- width: 100%;
208
- height: 100%;
209
- display: flex;
210
- align-items: center;
211
- justify-content: center;
212
- background: rgba(0, 0, 0, 0.9);
213
- color: white;
214
- z-index: 1000;
215
-
216
- .error-content {
217
- text-align: center;
218
- padding: 2rem;
219
- max-width: 400px;
220
-
221
- svg {
222
- color: #00adef;
223
- margin-bottom: 1rem;
224
- }
225
-
226
- .error-message {
227
- margin: 1rem 0;
228
- font-size: 1rem;
229
- line-height: 1.5;
230
- }
231
-
232
- .retry-button {
233
- margin-top: 1rem;
234
- padding: 0.75rem 1.5rem;
235
- background: #00adef;
236
- color: white;
237
- border: none;
238
- border-radius: 4px;
239
- cursor: pointer;
240
- font-size: 1rem;
241
- font-weight: 600;
242
- transition: background 0.2s ease;
243
-
244
- &:hover {
245
- background: #0088bf;
246
- }
247
-
248
- &:focus {
249
- outline: 2px solid white;
250
- outline-offset: 2px;
251
- }
252
- }
253
- }
13
+ @include embed-media-base;
254
14
  }
255
15
  }