@drawbridge/components 0.0.61 → 0.0.63

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.
package/dist/video.js CHANGED
@@ -78,17 +78,45 @@ var Loader = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime
78
78
  );
79
79
  var loader_default = Loader;
80
80
 
81
- // components/video.js
81
+ // components/icons/warning.js
82
82
  var import_jsx_runtime2 = require("react/jsx-runtime");
83
+ var Warning = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
84
+ "svg",
85
+ {
86
+ ...{
87
+ fill: "none",
88
+ stroke: "currentColor",
89
+ strokeWidth: 1.5,
90
+ viewBox: "0 0 24 24",
91
+ ...props
92
+ },
93
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
94
+ "path",
95
+ {
96
+ ...{
97
+ d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z",
98
+ strokeLinecap: "round",
99
+ strokeLinejoin: "round"
100
+ }
101
+ }
102
+ )
103
+ }
104
+ );
105
+ var warning_default = Warning;
106
+
107
+ // components/video.js
108
+ var import_jsx_runtime3 = require("react/jsx-runtime");
83
109
  var ReactPlayer = (0, import_dynamic.default)(
84
110
  () => import("react-player/lazy"),
85
111
  {
86
112
  ssr: false
87
113
  }
88
114
  );
115
+ var DEFER_FALLBACK_MS = 5e3;
89
116
  var Video = ({
90
117
  className,
91
118
  controls = false,
119
+ defer = false,
92
120
  loop = false,
93
121
  onEnded = () => {
94
122
  },
@@ -101,15 +129,18 @@ var Video = ({
101
129
  onPlay,
102
130
  playing = false,
103
131
  poster,
132
+ priority = false,
104
133
  reset = false,
105
134
  style = {},
106
135
  hls,
107
136
  mp4
108
137
  }) => {
109
- var _a, _b;
138
+ var _a, _b, _c, _d;
110
139
  const durationFired = (0, import_react.useRef)(false);
111
140
  const [player, setPlayer] = (0, import_react.useState)();
112
141
  const [videoUrl, setVideoUrl] = (0, import_react.useState)(hls ? hls : mp4);
142
+ const [mountPlayer, setMountPlayer] = (0, import_react.useState)(!defer);
143
+ const [posterPainted, setPosterPainted] = (0, import_react.useState)(false);
113
144
  const [failed, setFailed] = (0, import_react.useState)(false);
114
145
  (0, import_react.useEffect)(
115
146
  () => {
@@ -119,8 +150,36 @@ var Video = ({
119
150
  },
120
151
  [player, reset]
121
152
  );
122
- const inner = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react.Fragment, { children: [
123
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
153
+ (0, import_react.useEffect)(
154
+ () => {
155
+ if (!defer || mountPlayer || typeof window === "undefined") return;
156
+ if (!poster) {
157
+ setMountPlayer(true);
158
+ return;
159
+ }
160
+ let idle;
161
+ const start = () => setMountPlayer(true);
162
+ const soon = () => {
163
+ if ("requestIdleCallback" in window) {
164
+ idle = window.requestIdleCallback(start, { timeout: 300 });
165
+ } else {
166
+ idle = setTimeout(start, 100);
167
+ }
168
+ };
169
+ if (posterPainted) {
170
+ soon();
171
+ return () => {
172
+ if (idle && "cancelIdleCallback" in window) window.cancelIdleCallback(idle);
173
+ clearTimeout(idle);
174
+ };
175
+ }
176
+ const fallback = setTimeout(start, DEFER_FALLBACK_MS);
177
+ return () => clearTimeout(fallback);
178
+ },
179
+ [defer, mountPlayer, poster, posterPainted]
180
+ );
181
+ const inner = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react.Fragment, { children: [
182
+ mountPlayer && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
124
183
  ReactPlayer,
125
184
  {
126
185
  ...{
@@ -182,18 +241,28 @@ var Video = ({
182
241
  }
183
242
  }
184
243
  ),
185
- !player && poster && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
244
+ !player && poster && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
186
245
  "img",
187
246
  {
188
247
  ...{
189
248
  alt: "",
190
249
  "aria-hidden": true,
191
250
  className: "absolute inset-0 w-full h-full object-cover pointer-events-none",
251
+ decoding: "async",
252
+ ...priority ? { fetchpriority: "high", loading: "eager" } : { loading: "lazy" },
253
+ onLoad: () => setPosterPainted(true),
254
+ // A cached poster can finish loading before React attaches
255
+ // onLoad, so check completeness on attach too — otherwise the
256
+ // exact case this optimises for (warm revisit) would fall
257
+ // through to the 5s fallback.
258
+ ref: (element) => {
259
+ if ((element == null ? void 0 : element.complete) && element.naturalWidth > 0) setPosterPainted(true);
260
+ },
192
261
  src: poster
193
262
  }
194
263
  }
195
264
  ),
196
- !player && !poster && !failed && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
265
+ !player && !poster && !failed && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
197
266
  "div",
198
267
  {
199
268
  ...{
@@ -203,7 +272,7 @@ var Video = ({
203
272
  // already reserves its height) means removing it shifts nothing.
204
273
  className: "absolute inset-0 flex justify-center items-center"
205
274
  },
206
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
275
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
207
276
  loader_default,
208
277
  {
209
278
  ...{
@@ -215,9 +284,30 @@ var Video = ({
215
284
  }
216
285
  )
217
286
  }
287
+ ),
288
+ failed && !poster && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
289
+ "div",
290
+ {
291
+ ...{
292
+ className: "absolute inset-0 flex justify-center items-center"
293
+ },
294
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
295
+ warning_default,
296
+ {
297
+ ...{
298
+ "aria-label": "Video unavailable",
299
+ className: "w-10 h-10 opacity-40",
300
+ role: "img",
301
+ style: {
302
+ color: (_d = (_c = style == null ? void 0 : style.background) == null ? void 0 : _c.color) == null ? void 0 : _d.hex
303
+ }
304
+ }
305
+ }
306
+ )
307
+ }
218
308
  )
219
309
  ] });
220
- return className ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
310
+ return className ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
221
311
  "div",
222
312
  {
223
313
  ...{
package/dist/video.mjs CHANGED
@@ -2,6 +2,9 @@
2
2
  import {
3
3
  loader_default
4
4
  } from "./chunk-2ZYGRSSA.mjs";
5
+ import {
6
+ warning_default
7
+ } from "./chunk-Q3UIVGPQ.mjs";
5
8
 
6
9
  // components/video.js
7
10
  import dynamic from "next/dynamic";
@@ -13,9 +16,11 @@ var ReactPlayer = dynamic(
13
16
  ssr: false
14
17
  }
15
18
  );
19
+ var DEFER_FALLBACK_MS = 5e3;
16
20
  var Video = ({
17
21
  className,
18
22
  controls = false,
23
+ defer = false,
19
24
  loop = false,
20
25
  onEnded = () => {
21
26
  },
@@ -28,15 +33,18 @@ var Video = ({
28
33
  onPlay,
29
34
  playing = false,
30
35
  poster,
36
+ priority = false,
31
37
  reset = false,
32
38
  style = {},
33
39
  hls,
34
40
  mp4
35
41
  }) => {
36
- var _a, _b;
42
+ var _a, _b, _c, _d;
37
43
  const durationFired = useRef(false);
38
44
  const [player, setPlayer] = useState();
39
45
  const [videoUrl, setVideoUrl] = useState(hls ? hls : mp4);
46
+ const [mountPlayer, setMountPlayer] = useState(!defer);
47
+ const [posterPainted, setPosterPainted] = useState(false);
40
48
  const [failed, setFailed] = useState(false);
41
49
  useEffect(
42
50
  () => {
@@ -46,8 +54,36 @@ var Video = ({
46
54
  },
47
55
  [player, reset]
48
56
  );
57
+ useEffect(
58
+ () => {
59
+ if (!defer || mountPlayer || typeof window === "undefined") return;
60
+ if (!poster) {
61
+ setMountPlayer(true);
62
+ return;
63
+ }
64
+ let idle;
65
+ const start = () => setMountPlayer(true);
66
+ const soon = () => {
67
+ if ("requestIdleCallback" in window) {
68
+ idle = window.requestIdleCallback(start, { timeout: 300 });
69
+ } else {
70
+ idle = setTimeout(start, 100);
71
+ }
72
+ };
73
+ if (posterPainted) {
74
+ soon();
75
+ return () => {
76
+ if (idle && "cancelIdleCallback" in window) window.cancelIdleCallback(idle);
77
+ clearTimeout(idle);
78
+ };
79
+ }
80
+ const fallback = setTimeout(start, DEFER_FALLBACK_MS);
81
+ return () => clearTimeout(fallback);
82
+ },
83
+ [defer, mountPlayer, poster, posterPainted]
84
+ );
49
85
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
50
- /* @__PURE__ */ jsx(
86
+ mountPlayer && /* @__PURE__ */ jsx(
51
87
  ReactPlayer,
52
88
  {
53
89
  ...{
@@ -116,6 +152,16 @@ var Video = ({
116
152
  alt: "",
117
153
  "aria-hidden": true,
118
154
  className: "absolute inset-0 w-full h-full object-cover pointer-events-none",
155
+ decoding: "async",
156
+ ...priority ? { fetchpriority: "high", loading: "eager" } : { loading: "lazy" },
157
+ onLoad: () => setPosterPainted(true),
158
+ // A cached poster can finish loading before React attaches
159
+ // onLoad, so check completeness on attach too — otherwise the
160
+ // exact case this optimises for (warm revisit) would fall
161
+ // through to the 5s fallback.
162
+ ref: (element) => {
163
+ if ((element == null ? void 0 : element.complete) && element.naturalWidth > 0) setPosterPainted(true);
164
+ },
119
165
  src: poster
120
166
  }
121
167
  }
@@ -142,6 +188,27 @@ var Video = ({
142
188
  }
143
189
  )
144
190
  }
191
+ ),
192
+ failed && !poster && /* @__PURE__ */ jsx(
193
+ "div",
194
+ {
195
+ ...{
196
+ className: "absolute inset-0 flex justify-center items-center"
197
+ },
198
+ children: /* @__PURE__ */ jsx(
199
+ warning_default,
200
+ {
201
+ ...{
202
+ "aria-label": "Video unavailable",
203
+ className: "w-10 h-10 opacity-40",
204
+ role: "img",
205
+ style: {
206
+ color: (_d = (_c = style == null ? void 0 : style.background) == null ? void 0 : _c.color) == null ? void 0 : _d.hex
207
+ }
208
+ }
209
+ }
210
+ )
211
+ }
145
212
  )
146
213
  ] });
147
214
  return className ? /* @__PURE__ */ jsx(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawbridge/components",
3
- "version": "0.0.61",
3
+ "version": "0.0.63",
4
4
  "exports": {
5
5
  "./advertisement": {
6
6
  "types": "./types/advertisement.d.ts",