@uibit/video 0.1.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.
@@ -0,0 +1,36 @@
1
+ <script lang="ts">
2
+ import '@uibit/video';
3
+ import type { Video as HTMLElementClass } from '@uibit/video';
4
+
5
+ let {
6
+ poster = undefined,
7
+ controls = undefined,
8
+ children
9
+ } = $props<{
10
+ children?: any;
11
+ poster?: string;
12
+ controls?: boolean;
13
+
14
+ }>();
15
+
16
+ let elementRef: HTMLElementClass | null = $state(null);
17
+
18
+ $effect(() => {
19
+ if (elementRef && poster !== undefined) {
20
+ elementRef.poster = poster;
21
+ }
22
+ if (elementRef && controls !== undefined) {
23
+ elementRef.controls = controls;
24
+ }
25
+ });
26
+
27
+ </script>
28
+
29
+ <uibit-video bind:this={elementRef} {...$$restProps}>
30
+
31
+ {#if children}
32
+ {@render children()}
33
+ {:else}
34
+ <slot />
35
+ {/if}
36
+ </uibit-video>
@@ -0,0 +1,23 @@
1
+ import { defineComponent, h } from 'vue';
2
+ import type { Video as HTMLElementClass } from '@uibit/video';
3
+ import '@uibit/video';
4
+
5
+ export const Video = defineComponent({
6
+ name: 'Video',
7
+ props: {
8
+ poster: { type: [String, Number, Boolean, Array, Object] as any },
9
+ controls: { type: [String, Number, Boolean, Array, Object] as any }
10
+ },
11
+ emits: [],
12
+ setup(props, { slots, emit }) {
13
+ return () => {
14
+ const eventListeners: Record<string, any> = {};
15
+
16
+
17
+ return h('uibit-video', {
18
+ ...props,
19
+ ...eventListeners
20
+ }, slots.default?.());
21
+ };
22
+ }
23
+ });
@@ -0,0 +1,3 @@
1
+ export { default, Video } from './video';
2
+ export * from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACzC,cAAc,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default, Video } from './video';
2
+ export * from './types';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACzC,cAAc,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const styles: import("lit").CSSResult;
2
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM,yBA8RlB,CAAC"}
package/dist/styles.js ADDED
@@ -0,0 +1,289 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ display: block;
5
+ width: 100%;
6
+ font-size: var(--uibit-video-font-size, var(--uibit-font-size-sm, 0.875rem));
7
+ font-family: var(--uibit-video-font-family, inherit);
8
+ --uibit-video-radius: 0;
9
+ --uibit-video-bg: #000000;
10
+ --uibit-video-focus-color: #ffffff;
11
+ --uibit-video-control-color: #ffffff;
12
+ }
13
+
14
+ .player-container {
15
+ position: relative;
16
+ width: 100%;
17
+ overflow: hidden;
18
+ background-color: var(--uibit-video-bg);
19
+ border-radius: var(--uibit-video-radius);
20
+ aspect-ratio: 16 / 9;
21
+ user-select: none;
22
+ outline: none;
23
+ }
24
+
25
+ .player-container:focus-visible {
26
+ outline: 0.125rem solid var(--uibit-video-focus-color);
27
+ outline-offset: 0.125rem;
28
+ }
29
+
30
+ ::slotted(video) {
31
+ width: 100%;
32
+ height: 100%;
33
+ object-fit: contain;
34
+ display: block;
35
+ }
36
+
37
+ ::slotted(iframe) {
38
+ width: 100%;
39
+ height: 100%;
40
+ border: 0;
41
+ display: block;
42
+ }
43
+
44
+ .iframe-container {
45
+ width: 100%;
46
+ height: 100%;
47
+ }
48
+
49
+ /* ── Overlay / Poster ────────────────────────────────────────── */
50
+
51
+ .poster-overlay {
52
+ position: absolute;
53
+ inset: 0;
54
+ background-size: cover;
55
+ background-position: center;
56
+ display: flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ z-index: 10;
60
+ transition: opacity 0.3s ease;
61
+ }
62
+
63
+ /* Premium play button - circular, translucent white background with blur and cut-out see-through play icon */
64
+ .center-play-btn {
65
+ position: relative;
66
+ z-index: 11;
67
+ width: 4.5rem;
68
+ height: 4.5rem;
69
+ border-radius: 9999px;
70
+ background: rgba(255, 255, 255, 0.75);
71
+ backdrop-filter: blur(0.5rem);
72
+ -webkit-backdrop-filter: blur(0.5rem);
73
+ border: none;
74
+ cursor: pointer;
75
+ display: flex;
76
+ align-items: center;
77
+ justify-content: center;
78
+ box-shadow: none;
79
+ opacity: 0.9;
80
+ transition: opacity 0.2s ease, background-color 0.2s ease;
81
+
82
+ /* Mask out the play icon so it is see-through */
83
+ mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><mask id='m'><rect x='0' y='0' width='100' height='100' fill='white'/><polygon points='38,28 75,50 38,72' fill='black'/></mask><circle cx='50' cy='50' r='50' fill='white' mask='url(%23m)'/></svg>") no-repeat center / contain;
84
+ -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><mask id='m'><rect x='0' y='0' width='100' height='100' fill='white'/><polygon points='38,28 75,50 38,72' fill='black'/></mask><circle cx='50' cy='50' r='50' fill='white' mask='url(%23m)'/></svg>") no-repeat center / contain;
85
+ }
86
+
87
+ .center-play-btn:hover {
88
+ opacity: 1;
89
+ background: rgba(255, 255, 255, 0.9);
90
+ }
91
+
92
+ .center-play-btn:active {
93
+ opacity: 0.8;
94
+ }
95
+
96
+ /* ── Minimal Single-Row Controls Bar ────────────────────────── */
97
+
98
+ .controls-bar {
99
+ position: absolute;
100
+ bottom: 0;
101
+ left: 0;
102
+ right: 0;
103
+ z-index: 20;
104
+ display: flex;
105
+ align-items: center;
106
+ gap: 1rem;
107
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.5), transparent); /* Vignette gradient */
108
+ padding: 1.25rem 1.5rem;
109
+ color: var(--uibit-video-control-color);
110
+ opacity: 0;
111
+ transition: opacity 0.2s ease;
112
+ }
113
+
114
+ /* Show controls on hover, focus, or when paused */
115
+ .player-container:hover .controls-bar,
116
+ .player-container:focus-within .controls-bar,
117
+ .player-container.paused .controls-bar,
118
+ .player-container.seeking .controls-bar {
119
+ opacity: 1;
120
+ }
121
+
122
+ .control-btn {
123
+ background: transparent;
124
+ border: none;
125
+ color: inherit;
126
+ cursor: pointer;
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ width: 2.5rem; /* Larger hit target (40px) */
131
+ height: 2.5rem; /* Larger hit target (40px) */
132
+ padding: 0;
133
+ opacity: 0.8;
134
+ transition: transform 0.2s ease, opacity 0.2s ease;
135
+ }
136
+
137
+ .control-btn:hover {
138
+ opacity: 1;
139
+ transform: scale(1.05);
140
+ }
141
+
142
+ .control-btn:active {
143
+ transform: scale(0.95);
144
+ }
145
+
146
+ .control-btn:focus-visible {
147
+ outline: 0.125rem solid #ffffff;
148
+ }
149
+
150
+ .control-btn svg {
151
+ width: 1.125rem;
152
+ height: 1.125rem;
153
+ }
154
+
155
+ .time-display {
156
+ font-size: 0.75rem;
157
+ font-variant-numeric: tabular-nums;
158
+ font-weight: 500;
159
+ opacity: 0.9;
160
+ white-space: nowrap;
161
+ }
162
+
163
+ /* ── Timeline (Flex-Grow) ────────────────────────────────────── */
164
+
165
+ .timeline-container {
166
+ flex-grow: 1;
167
+ height: 2rem; /* Larger hit target (32px height) */
168
+ display: flex;
169
+ align-items: center;
170
+ cursor: pointer;
171
+ position: relative;
172
+ }
173
+
174
+ .timeline-bar {
175
+ width: 100%;
176
+ height: 0.125rem; /* Ultra thin line */
177
+ background: rgba(255, 255, 255, 0.25);
178
+ position: relative;
179
+ transition: height 0.15s ease;
180
+ }
181
+
182
+ .timeline-container:hover .timeline-bar {
183
+ height: 0.25rem;
184
+ }
185
+
186
+ .timeline-progress {
187
+ height: 100%;
188
+ background: #ffffff;
189
+ position: absolute;
190
+ left: 0;
191
+ top: 0;
192
+ }
193
+
194
+ /* Handle is circular, borderless, shadowless */
195
+ .timeline-handle {
196
+ width: 0.625rem;
197
+ height: 0.625rem;
198
+ border-radius: 9999px;
199
+ background: #ffffff;
200
+ position: absolute;
201
+ top: 50%;
202
+ transform: translate(-50%, -50%) scale(0);
203
+ transition: transform 0.15s ease;
204
+ box-shadow: none;
205
+ border: none;
206
+ }
207
+
208
+ .timeline-container:hover .timeline-handle,
209
+ .timeline-container:active .timeline-handle {
210
+ transform: translate(-50%, -50%) scale(1);
211
+ }
212
+
213
+ /* ── Volume Slider ───────────────────────────────────────────── */
214
+
215
+ .volume-container {
216
+ display: flex;
217
+ align-items: center;
218
+ gap: 0.5rem;
219
+ }
220
+
221
+ .volume-slider-wrap {
222
+ width: 0;
223
+ overflow: hidden;
224
+ height: 2rem; /* Matches button height for hit alignment */
225
+ display: flex;
226
+ align-items: center;
227
+ transition: width 0.2s ease;
228
+ }
229
+
230
+ .volume-container:hover .volume-slider-wrap {
231
+ width: 3.5rem;
232
+ }
233
+
234
+ .volume-slider-container {
235
+ width: 100%;
236
+ height: 2rem; /* Larger hit target (32px height) */
237
+ display: flex;
238
+ align-items: center;
239
+ cursor: pointer;
240
+ position: relative;
241
+ outline: none;
242
+ padding: 0 0.3125rem; /* Inset track slightly so the handle does not clip on the edges */
243
+ box-sizing: border-box;
244
+ }
245
+
246
+ .volume-slider-bar {
247
+ width: 100%;
248
+ height: 0.125rem; /* Ultra thin line */
249
+ background: rgba(255, 255, 255, 0.25);
250
+ position: relative;
251
+ transition: height 0.15s ease;
252
+ }
253
+
254
+ .volume-container:hover .volume-slider-bar,
255
+ .volume-slider-container:hover .volume-slider-bar {
256
+ height: 0.25rem;
257
+ }
258
+
259
+ .volume-slider-progress {
260
+ height: 100%;
261
+ background: #ffffff;
262
+ position: absolute;
263
+ left: 0;
264
+ top: 0;
265
+ }
266
+
267
+ .volume-slider-handle {
268
+ width: 0.625rem;
269
+ height: 0.625rem;
270
+ border-radius: 9999px;
271
+ background: #ffffff;
272
+ position: absolute;
273
+ top: 50%;
274
+ transform: translate(-50%, -50%) scale(0);
275
+ transition: transform 0.15s ease;
276
+ box-shadow: none;
277
+ border: none;
278
+ }
279
+
280
+ .volume-container:hover .volume-slider-handle {
281
+ transform: translate(-50%, -50%) scale(1);
282
+ }
283
+
284
+ /* Hide raw slots */
285
+ .hidden-slot-wrap {
286
+ display: none;
287
+ }
288
+ `;
289
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8RxB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type Video from './video';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'uibit-video': Video;
5
+ }
6
+ }
7
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AAEjC,OAAO,CAAC,MAAM,CAAC;IACf,UAAU,qBAAqB;QAAG,aAAa,EAAE,KAAK,CAAC;KACtD;CACA"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ import type { PropertyValues } from 'lit';
2
+ import { UIBitElement } from '@uibit/core';
3
+ /**
4
+ * Enhanced custom video component that wraps a native `<video>` or `<iframe>` element.
5
+ * Provides custom interactive player controls with Scandinavian design aesthetics.
6
+ *
7
+ * @slot - The default slot where the native `<video>` or `<iframe>` element is placed.
8
+ *
9
+ * @cssprop [--uibit-video-radius=0.5rem] - Border radius of the video player.
10
+ * @cssprop [--uibit-video-bg=#000000] - Background color of the video player.
11
+ * @cssprop [--uibit-video-focus-color=#000000] - Focus outline color.
12
+ * @cssprop [--uibit-video-control-bg=rgba(17, 24, 39, 0.85)] - Background of the control bar.
13
+ * @cssprop [--uibit-video-control-border=rgba(255, 255, 255, 0.1)] - Border of the control bar.
14
+ * @cssprop [--uibit-video-control-color=#ffffff] - Color of icons and text.
15
+ */
16
+ export declare class Video extends UIBitElement {
17
+ static styles: import("lit").CSSResult;
18
+ /** Poster image URL. Also used as background for iframes before playing. */
19
+ poster: string;
20
+ /** Show player controls. */
21
+ controls: boolean;
22
+ private _isPlaying;
23
+ private _currentTime;
24
+ private _duration;
25
+ private _volume;
26
+ private _isMuted;
27
+ private _isFullscreen;
28
+ private _isSeeking;
29
+ private _isVolumeSeeking;
30
+ private _isIframeMode;
31
+ private _iframePlaying;
32
+ private _containerEl?;
33
+ private _videoEl;
34
+ private _iframeEl;
35
+ connectedCallback(): void;
36
+ firstUpdated(changedProperties: PropertyValues): void;
37
+ private _detectSlottedElements;
38
+ private _setupVideoListeners;
39
+ private _onSlotChange;
40
+ togglePlay(): void;
41
+ private _playIframe;
42
+ toggleMute(): void;
43
+ private _onVolumePointerDown;
44
+ private _onVolumePointerMove;
45
+ private _onVolumePointerUp;
46
+ private _updateVolumeFromEvent;
47
+ toggleFullscreen(): void;
48
+ private _onFullscreenChange;
49
+ private _onTimelinePointerDown;
50
+ private _onTimelinePointerMove;
51
+ private _onTimelinePointerUp;
52
+ private _updateTimelineFromEvent;
53
+ private _onKeyDown;
54
+ private _formatTime;
55
+ private _onPlayerClick;
56
+ render(): import("lit").TemplateResult<1>;
57
+ }
58
+ export default Video;
59
+ //# sourceMappingURL=video.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../src/video.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EAA2C,YAAY,EAAE,MAAM,aAAa,CAAC;AAKpF;;;;;;;;;;;;GAYG;AACH,qBACa,KAAM,SAAQ,YAAY;IACrC,MAAM,CAAC,MAAM,0BAAU;IAEvB,4EAA4E;IAChD,MAAM,SAAM;IAExC,4BAA4B;IACC,QAAQ,UAAQ;IAEpC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAAS;IAEZ,OAAO,CAAC,YAAY,CAAC,CAAc;IAE/D,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,SAAS,CAAkC;IAEnD,iBAAiB,SAGhB;IAED,YAAY,CAAC,iBAAiB,EAAE,cAAc,QAG7C;IAED,OAAO,CAAC,sBAAsB;IA8B9B,OAAO,CAAC,oBAAoB;IAuC5B,OAAO,CAAC,aAAa;IAMrB,UAAU,SAYT;IAED,OAAO,CAAC,WAAW;IAcnB,UAAU,SAIT;IAED,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,sBAAsB;IAY9B,gBAAgB,SASf;IAED,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,sBAAsB;IAQ9B,OAAO,CAAC,sBAAsB;IAK9B,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,wBAAwB;IAWhC,OAAO,CAAC,UAAU;IAiClB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,cAAc;IAUtB,MAAM,oCA+HL;CACF;eAEc,KAAK"}