@wix/editor-react-components 1.2812.0 → 1.2813.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.
@@ -29,14 +29,19 @@ const getScrollSpaceHeight = (duration, speed, start) => {
29
29
  const getScrubProgress = (root2, stage2, {
30
30
  start,
31
31
  viewportHeight,
32
- stickyTop
32
+ stickyTop,
33
+ sticky = true
33
34
  }) => {
34
35
  const rootRect = root2.getBoundingClientRect();
35
- const stageRect = stage2.getBoundingClientRect();
36
- const travel = Math.max(0, rootRect.height - stageRect.height);
37
36
  const part = START_LINE[start];
38
37
  const line = part === void 0 ? stickyTop : Math.max(part * viewportHeight, stickyTop);
39
38
  const preRoll = line - stickyTop;
39
+ if (!sticky) {
40
+ const length = preRoll + rootRect.height;
41
+ return length > 0 ? clamp((line - rootRect.top) / length, 0, 1) : 0;
42
+ }
43
+ const stageRect = stage2.getBoundingClientRect();
44
+ const travel = Math.max(0, rootRect.height - stageRect.height);
40
45
  const distance = preRoll + travel;
41
46
  if (!(distance > 0)) {
42
47
  return 0;
@@ -177,7 +182,9 @@ const useScrubProgress = ({
177
182
  getScrubProgress(root2, stage2, {
178
183
  start,
179
184
  viewportHeight: window.innerHeight,
180
- stickyTop: parseFloat(stageStyle.top) || 0
185
+ stickyTop: parseFloat(stageStyle.top) || 0,
186
+ // The Sticky design option turns it off in CSS only (VideoScrub.module.scss).
187
+ sticky: stageStyle.position === "sticky"
181
188
  })
182
189
  );
183
190
  const tick = () => {
@@ -424,6 +431,46 @@ function useTimeframes({
424
431
  frameShown: editing && frameShown
425
432
  };
426
433
  }
434
+ const useVideoDuration = ({
435
+ savedDuration,
436
+ videoRef,
437
+ videoKey
438
+ }) => {
439
+ const [loadedDuration, setLoadedDuration] = useState(0);
440
+ useEffect(() => {
441
+ setLoadedDuration(0);
442
+ const video = videoRef.current;
443
+ if (savedDuration || !video) {
444
+ return void 0;
445
+ }
446
+ const read = () => setLoadedDuration(
447
+ Number.isFinite(video.duration) && video.duration > 0 ? video.duration : 0
448
+ );
449
+ let requestedSrc = "";
450
+ const loadMetadata = () => {
451
+ const src = video.getAttribute("src") || video.currentSrc;
452
+ if (!src || src === requestedSrc || video.readyState >= HTMLMediaElement.HAVE_METADATA) {
453
+ return;
454
+ }
455
+ requestedSrc = src;
456
+ if (video.preload === "none") {
457
+ video.preload = "metadata";
458
+ }
459
+ video.load();
460
+ };
461
+ video.addEventListener("loadstart", loadMetadata);
462
+ video.addEventListener("loadedmetadata", read);
463
+ video.addEventListener("durationchange", read);
464
+ loadMetadata();
465
+ read();
466
+ return () => {
467
+ video.removeEventListener("loadstart", loadMetadata);
468
+ video.removeEventListener("loadedmetadata", read);
469
+ video.removeEventListener("durationchange", read);
470
+ };
471
+ }, [savedDuration, videoRef, videoKey]);
472
+ return savedDuration || loadedDuration;
473
+ };
427
474
  const root = "root__Wv1E1";
428
475
  const stage = "stage__XFpev";
429
476
  const media = "media__tTFno";
@@ -470,7 +517,11 @@ const VideoScrub = ({
470
517
  const rootRef = useRef(null);
471
518
  const stageRef = useRef(null);
472
519
  const videoRef = useRef(null);
473
- const duration = (video == null ? void 0 : video.duration) ?? 0;
520
+ const duration = useVideoDuration({
521
+ savedDuration: video == null ? void 0 : video.duration,
522
+ videoRef,
523
+ videoKey: video == null ? void 0 : video.uri
524
+ });
474
525
  const { layout, seek } = useScrubGate({ scrubAllowed, duration });
475
526
  const { seekProgress, frameReady: frameReady2 } = useScrubVideo({
476
527
  enabled: seek,
@@ -1,10 +1,18 @@
1
1
  import { ScrollSpeed, ScrubStart } from './VideoScrub.types';
2
- export declare const COMPONENT_TYPE = "wixEditorElements.VideoScrub__DEV__v11";
2
+ export declare const COMPONENT_TYPE = "wixEditorElements.VideoScrub__DEV__v14";
3
3
  export declare const ROOT_CLASS = "video-scrub";
4
4
  export declare const presets: {
5
- readonly free: "free";
5
+ readonly resizable: "resizable";
6
6
  readonly stretched: "stretched";
7
7
  };
8
+ export declare const PRESET_THUMBNAILS: {
9
+ readonly stretched: "https://static.wixstatic.com/media/18873e_d780aeec5db34595bafd5f0d806b834b~mv2.png";
10
+ readonly resizable: "https://static.wixstatic.com/media/18873e_7db03132e6d8443da903c91f02616b90~mv2.png";
11
+ };
12
+ export declare const StickyMode: {
13
+ readonly on: "on";
14
+ readonly off: "off";
15
+ };
8
16
  export declare const DEFAULT_VIDEO_RATIO: number;
9
17
  export declare const SCROLL_VH_PER_SECOND: Record<ScrollSpeed, number>;
10
18
  export declare const MIN_SCROLL_VH = 50;
@@ -38,6 +38,9 @@
38
38
  --borderEndStartRadius: initial;
39
39
  --borderEndEndRadius: initial;
40
40
  --aspect-ratio: initial;
41
+ --video-scrub-stage-position: initial;
42
+ --video-scrub-stage-top: initial;
43
+ --video-scrub-scroll-space: initial;
41
44
  position: relative;
42
45
  box-sizing: border-box;
43
46
  }
@@ -85,13 +88,17 @@
85
88
  }
86
89
 
87
90
  .scrubbing__yEgJI .stage__XFpev {
88
- position: sticky;
89
- top: var(--video-scrub-sticky-top);
91
+ position: var(--video-scrub-stage-position, sticky);
92
+ top: var(--video-scrub-stage-top, var(--video-scrub-sticky-top));
90
93
  transition: top var(--wix-top-inset-transition-duration, 0ms) var(--wix-top-inset-transition-easing, linear);
91
94
  height: var(--video-scrub-stage-height, inherit);
92
95
  aspect-ratio: 1/var(--aspect-ratio);
93
96
  }
94
97
 
98
+ .scrollSpace__oaKzu {
99
+ display: var(--video-scrub-scroll-space, block);
100
+ }
101
+
95
102
  @media (prefers-reduced-motion: reduce) {
96
103
  .scrollSpace__oaKzu {
97
104
  display: none;
@@ -0,0 +1,11 @@
1
+ import { RefObject } from 'react';
2
+ /**
3
+ * The video's length in seconds. Replace Video (GFPP) saves `duration`, but a video picked in the
4
+ * Settings panel is saved without it, so then it comes from the video element once its metadata
5
+ * loads. 0 until known.
6
+ */
7
+ export declare const useVideoDuration: ({ savedDuration, videoRef, videoKey, }: {
8
+ savedDuration?: number;
9
+ videoRef: RefObject<HTMLVideoElement | null>;
10
+ videoKey?: string;
11
+ }) => number;
@@ -1,24 +1,18 @@
1
1
  import { L as LAYOUT, b as DISPLAY_GROUPS, C as CSS_PROPERTIES, M as MEDIA, D as DATA, c as ContainerType, A as Archetype } from "../chunks/chunk-LDITHLYN.js";
2
2
  import { g as getTranslationResources } from "../chunks/translationResources.js";
3
3
  import { V as VideoCategoryTypes } from "../chunks/types.impl.js";
4
- import { p as presets, k as TIMEFRAMES_GROUP_KEY, a as ScrollSpeed, j as ScrubStart, T as TIMEFRAME_CONTENT_CLASS, l as MAX_COUNT, R as ROOT_CLASS, C as COMPONENT_TYPE } from "../chunks/types.js";
4
+ import { p as presets, k as TIMEFRAMES_GROUP_KEY, a as ScrollSpeed, j as ScrubStart, P as PRESET_THUMBNAILS, l as StickyMode, T as TIMEFRAME_CONTENT_CLASS, m as MAX_COUNT, R as ROOT_CLASS, C as COMPONENT_TYPE } from "../chunks/types.js";
5
5
  const manifest = {
6
- id: "0dab4e56-b218-41ae-baef-a041df9f12e1",
6
+ id: "550e742a-512c-410c-a721-d805f781c5bc",
7
7
  type: COMPONENT_TYPE,
8
8
  description: "A video that plays by page scroll: while the visitor scrolls past it, the video stays on screen and its time follows the scroll. Timeframes show elements over the video during parts of it.",
9
9
  installation: {
10
10
  initialSize: {
11
- width: {
12
- sizingType: LAYOUT.SIZING_TYPE.pixels,
13
- pixels: 640
14
- },
15
- height: {
16
- sizingType: LAYOUT.SIZING_TYPE.pixels,
17
- pixels: 360
18
- }
11
+ width: { sizingType: LAYOUT.SIZING_TYPE.stretched },
12
+ height: { sizingType: LAYOUT.SIZING_TYPE.content }
19
13
  },
20
14
  presets: {
21
- default: presets.free
15
+ default: presets.stretched
22
16
  }
23
17
  },
24
18
  editorElement: {
@@ -231,6 +225,42 @@ const manifest = {
231
225
  displayName: "Bottom End Corner",
232
226
  cssPropertyType: CSS_PROPERTIES.CSS_PROPERTY_TYPE.borderEndEndRadius,
233
227
  defaultValue: "0px"
228
+ },
229
+ // On: the video stays on screen while it scrubs, over a tall scroll track. Off: the root is
230
+ // only the video, and it scrubs while it scrolls past. CSS only, so the server render is
231
+ // right (VideoScrub.module.scss).
232
+ sticky: {
233
+ displayName: "Sticky video",
234
+ cssPropertyType: CSS_PROPERTIES.CSS_PROPERTY_TYPE.customEnum,
235
+ defaultValue: StickyMode.on,
236
+ customEnum: {
237
+ cssPropertyType: CSS_PROPERTIES.CSS_PROPERTY_TYPE.string,
238
+ options: [
239
+ {
240
+ value: StickyMode.on,
241
+ displayName: "On",
242
+ appliedStyles: [
243
+ { property: "--video-scrub-stage-position", value: "sticky" },
244
+ // Both options set the same properties, so one breakpoint's value never leaks
245
+ // into another's.
246
+ {
247
+ property: "--video-scrub-stage-top",
248
+ value: "var(--video-scrub-sticky-top)"
249
+ },
250
+ { property: "--video-scrub-scroll-space", value: "block" }
251
+ ]
252
+ },
253
+ {
254
+ value: StickyMode.off,
255
+ displayName: "Off",
256
+ appliedStyles: [
257
+ { property: "--video-scrub-stage-position", value: "relative" },
258
+ { property: "--video-scrub-stage-top", value: "0px" },
259
+ { property: "--video-scrub-scroll-space", value: "none" }
260
+ ]
261
+ }
262
+ ]
263
+ }
234
264
  }
235
265
  },
236
266
  displayGroups: {
@@ -280,6 +310,12 @@ const manifest = {
280
310
  style: "displayGroups.borderStyleGroup"
281
311
  }
282
312
  },
313
+ stickyGroup: {
314
+ groupType: DISPLAY_GROUPS.GROUP_TYPE.cssDataType,
315
+ cssDataType: {
316
+ items: ["sticky"]
317
+ }
318
+ },
283
319
  cornersGroup: {
284
320
  groupType: DISPLAY_GROUPS.GROUP_TYPE.borderRadius,
285
321
  displayName: "Corner radius",
@@ -290,12 +326,13 @@ const manifest = {
290
326
  bottomRight: "borderEndEndRadius"
291
327
  }
292
328
  },
293
- // The native presets panel (Explore Designs), like Wix Gallery.
329
+ // The native presets panel (Explore Designs). One group, so the panel shows no tabs. The
330
+ // panel lists Resizable first whatever this order is.
294
331
  layouts: {
295
332
  groupType: DISPLAY_GROUPS.GROUP_TYPE.presets,
296
333
  displayName: "Layouts",
297
334
  presets: {
298
- items: [presets.free, presets.stretched]
335
+ items: [presets.stretched, presets.resizable]
299
336
  }
300
337
  },
301
338
  // The Settings panel does not follow the `data` key order.
@@ -307,33 +344,31 @@ const manifest = {
307
344
  }
308
345
  },
309
346
  presets: {
310
- [presets.free]: {
311
- displayName: "Free",
312
- // TODO: a real Video Scrub thumbnail. Borrowed from Wix Gallery for the spike.
313
- thumbnailUrl: "https://static.wixstatic.com/media/a9ff3b_e6ae88d12db9412498e72af65ce87c19~mv2.png",
347
+ [presets.stretched]: {
348
+ presetCssUrl: `./site/components/VideoScrub/presets/${presets.stretched}.css`,
349
+ displayName: "Stretched",
350
+ thumbnailUrl: PRESET_THUMBNAILS.stretched,
314
351
  initialSize: {
315
- width: { sizingType: LAYOUT.SIZING_TYPE.pixels, pixels: 640 },
316
- height: { sizingType: LAYOUT.SIZING_TYPE.pixels, pixels: 360 }
352
+ width: { sizingType: LAYOUT.SIZING_TYPE.stretched },
353
+ height: { sizingType: LAYOUT.SIZING_TYPE.content }
317
354
  },
318
355
  presetDefaults: {
319
356
  layout: {
320
- resizeDirection: LAYOUT.RESIZE_DIRECTION.horizontalAndVertical,
357
+ resizeDirection: LAYOUT.RESIZE_DIRECTION.none,
321
358
  disableStretching: true
322
359
  }
323
360
  }
324
361
  },
325
- [presets.stretched]: {
326
- presetCssUrl: `./site/components/VideoScrub/presets/${presets.stretched}.css`,
327
- displayName: "Stretched",
328
- // TODO: a real Video Scrub thumbnail. Borrowed from Wix Gallery for the spike.
329
- thumbnailUrl: "https://static.wixstatic.com/media/a9ff3b_9e4382b1d2e64e4a9ab56cc128439bd8~mv2.png",
362
+ [presets.resizable]: {
363
+ displayName: "Resizable",
364
+ thumbnailUrl: PRESET_THUMBNAILS.resizable,
330
365
  initialSize: {
331
- width: { sizingType: LAYOUT.SIZING_TYPE.stretched },
332
- height: { sizingType: LAYOUT.SIZING_TYPE.content }
366
+ width: { sizingType: LAYOUT.SIZING_TYPE.pixels, pixels: 640 },
367
+ height: { sizingType: LAYOUT.SIZING_TYPE.pixels, pixels: 360 }
333
368
  },
334
369
  presetDefaults: {
335
370
  layout: {
336
- resizeDirection: LAYOUT.RESIZE_DIRECTION.none,
371
+ resizeDirection: LAYOUT.RESIZE_DIRECTION.horizontalAndVertical,
337
372
  disableStretching: true
338
373
  }
339
374
  }
@@ -20,9 +20,13 @@ export declare const getScrollSpaceHeight: (duration: number, speed: ScrollSpeed
20
20
  *
21
21
  * The stuck part is how far the stage moved down its root, so the header and Wix Ads offsets need
22
22
  * no math there. `viewportHeight` and `stickyTop` are used only for the pre-roll of an early start.
23
+ *
24
+ * Not sticky (the Sticky design option is off): the root is only the video, and it scrubs while it
25
+ * scrolls from the start line until its bottom passes the sticky top (0 then: the stage's `top`).
23
26
  */
24
- export declare const getScrubProgress: (root: Element, stage: Element, { start, viewportHeight, stickyTop, }: {
27
+ export declare const getScrubProgress: (root: Element, stage: Element, { start, viewportHeight, stickyTop, sticky, }: {
25
28
  start: ScrubStart;
26
29
  viewportHeight: number;
27
30
  stickyTop: number;
31
+ sticky?: boolean;
28
32
  }) => number;
@@ -10,12 +10,20 @@ var ScrubStart = /* @__PURE__ */ ((ScrubStart2) => {
10
10
  ScrubStart2["top"] = "top";
11
11
  return ScrubStart2;
12
12
  })(ScrubStart || {});
13
- const COMPONENT_TYPE = "wixEditorElements.VideoScrub__DEV__v11";
13
+ const COMPONENT_TYPE = "wixEditorElements.VideoScrub__DEV__v14";
14
14
  const ROOT_CLASS = "video-scrub";
15
15
  const presets = {
16
- free: "free",
16
+ resizable: "resizable",
17
17
  stretched: "stretched"
18
18
  };
19
+ const PRESET_THUMBNAILS = {
20
+ stretched: "https://static.wixstatic.com/media/18873e_d780aeec5db34595bafd5f0d806b834b~mv2.png",
21
+ resizable: "https://static.wixstatic.com/media/18873e_7db03132e6d8443da903c91f02616b90~mv2.png"
22
+ };
23
+ const StickyMode = {
24
+ on: "on",
25
+ off: "off"
26
+ };
19
27
  const DEFAULT_VIDEO_RATIO = 9 / 16;
20
28
  const SCROLL_VH_PER_SECOND = {
21
29
  [ScrollSpeed.slow]: 30,
@@ -51,6 +59,7 @@ export {
51
59
  DEFAULT_VIDEO_RATIO as D,
52
60
  LEGACY_TIMEFRAMES_ARIA_LABEL_KEY as L,
53
61
  MAX_SCROLL_VH as M,
62
+ PRESET_THUMBNAILS as P,
54
63
  ROOT_CLASS as R,
55
64
  STICKY_TOP as S,
56
65
  TIMEFRAME_CONTENT_CLASS as T,
@@ -65,6 +74,7 @@ export {
65
74
  isDuration as i,
66
75
  ScrubStart as j,
67
76
  TIMEFRAMES_GROUP_KEY as k,
68
- MAX_COUNT as l,
77
+ StickyMode as l,
78
+ MAX_COUNT as m,
69
79
  presets as p
70
80
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/editor-react-components",
3
- "version": "1.2812.0",
3
+ "version": "1.2813.0",
4
4
  "description": "React components for the Wix Editor",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -224,5 +224,5 @@
224
224
  "registry": "https://registry.npmjs.org/",
225
225
  "access": "public"
226
226
  },
227
- "falconPackageHash": "db2dc4c2786e0c1a74db536e48c8d37ce5caac29cf5dceeae5f39a23"
227
+ "falconPackageHash": "0c6c4253b10c03d8953b8a008299c366f0bf518734fe5debf1e27950"
228
228
  }