@wix/editor-react-components 1.2748.0 → 1.2749.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,22 @@
1
+ import { default as React, AriaAttributes, ReactNode } from 'react';
2
+ export type TimeframeLayerItem = {
3
+ /** The timeframe's `timeframeIdentifier` (runtime props have no `_id`). Never the index: that would mix up container state after a split. */
4
+ key: string;
5
+ content: ReactNode;
6
+ };
7
+ export type TimeframeLayerProps = {
8
+ /** Same order as the timeframes. */
9
+ items: ReadonlyArray<TimeframeLayerItem>;
10
+ activeIndex: number | undefined;
11
+ className?: string;
12
+ /**
13
+ * The layer's label, from the parent's `a11y` data (already converted with
14
+ * `convertA11yKeysToHtmlFormat`). Focus falls back to the layer, so it needs a name.
15
+ */
16
+ a11yAttributes?: AriaAttributes;
17
+ };
18
+ /**
19
+ * Shows the active timeframe's content on top of the video. All items stay mounted (the inactive
20
+ * ones hidden) on purpose: the server HTML then holds every timeframe's content, for SEO.
21
+ */
22
+ export declare function TimeframeLayer({ items, activeIndex, className, a11yAttributes, }: TimeframeLayerProps): React.JSX.Element;
@@ -0,0 +1,86 @@
1
+ import { Timeframe, NewTimeframe, Result, NewTimeframeId, Rules } from './types';
2
+ /**
3
+ * One timeframe from 0 to DEFAULT_TIMEFRAME_MS (or the whole video if it is shorter), with a new
4
+ * timeframeIdentifier. No container key, so the editor makes an empty one. A video shorter than
5
+ * MIN_LENGTH_MS has room for no timeframe, so the list is empty.
6
+ */
7
+ export declare function createInitial(durationMs: number, { newTimeframeId, }?: {
8
+ newTimeframeId?: NewTimeframeId;
9
+ }): Array<NewTimeframe>;
10
+ /**
11
+ * A new timeframe that starts at `atMs`, in a gap. Its length is DEFAULT_TIMEFRAME_MS, or less when
12
+ * the next timeframe or the end of the video comes first. It fails with insideTimeframe when `atMs`
13
+ * is inside a timeframe (a timeframe's own end is not inside it), and with noRoom when less than
14
+ * MIN_LENGTH_MS fits. No container key, so the editor makes an empty one.
15
+ * `result.index` is the new timeframe's position.
16
+ */
17
+ export declare function add(list: ReadonlyArray<Timeframe>, atMs: number, rules: Rules): Result;
18
+ /** Cuts the timeframe that contains `atMs` in two. In a gap it fails with inGap. */
19
+ export declare function split(list: ReadonlyArray<Timeframe>, atMs: number, rules: Rules): Result;
20
+ export type Edge = 'start' | 'end';
21
+ /**
22
+ * Drags one edge of `list[index]` to `atMs`. Moving into a gap changes only this timeframe. When the
23
+ * edge reaches a neighbor, it keeps pushing: the neighbor's touching edge moves too, so the
24
+ * neighbor gets shorter. It never pushes past one neighbor. It fails with tooShort when this
25
+ * timeframe or the neighbor would be under MIN_LENGTH_MS; use edgeLimits to clamp a drag first.
26
+ */
27
+ export declare function resizeEdge(list: ReadonlyArray<Timeframe>, index: number, edge: Edge, atMs: number, rules: Rules): Result;
28
+ /**
29
+ * The range `resizeEdge` accepts for one edge: this timeframe and the neighbor it may push both keep
30
+ * MIN_LENGTH_MS, and the edge stays inside `[0, durationMs]`. Undefined for an unknown index.
31
+ * On broken saved data `minMs` can be more than `maxMs`: then no drag is possible.
32
+ */
33
+ export declare function edgeLimits(list: ReadonlyArray<Timeframe>, index: number, edge: Edge, rules: Rules): {
34
+ minMs: number;
35
+ maxMs: number;
36
+ } | undefined;
37
+ /**
38
+ * The `startMs` range `moveTimeframe` can reach for `list[index]`, keeping its length. It may push
39
+ * every timeframe before it to 0 and every timeframe after it to durationMs, so: from the total
40
+ * length of the timeframes before it, to durationMs minus its own length and the total length of
41
+ * the timeframes after it. Gaps do not count, because a push uses them up. Undefined for an unknown
42
+ * index. On broken saved data (timeframes longer than the video) `minMs` can be more than `maxMs`.
43
+ */
44
+ export declare function moveLimits(list: ReadonlyArray<Timeframe>, index: number, rules: Rules): {
45
+ minMs: number;
46
+ maxMs: number;
47
+ } | undefined;
48
+ /**
49
+ * Moves the whole timeframe `list[index]` so it starts at `startMs`, keeping its length. When it
50
+ * reaches a neighbor it pushes it, and that neighbor pushes the next one, as a chain: each pushed
51
+ * timeframe keeps its length, gaps are used up first, and a timeframe moves only when it is reached.
52
+ * `startMs` is clamped to moveLimits, so the last pushed timeframe stops at 0 or at durationMs.
53
+ * The order never changes and `result.index` is `index`. Only times change; `_id`,
54
+ * `timeframeIdentifier`, `name` and `container` stay. Errors: notFound, badTime (not a whole
55
+ * number), and the usual result checks (on broken saved data, see moveLimits).
56
+ */
57
+ export declare function moveTimeframe(list: ReadonlyArray<Timeframe>, index: number, startMs: number, rules: Rules): Result;
58
+ /**
59
+ * Removes a timeframe and leaves a gap: no neighbor gets its time. Removing the only timeframe is
60
+ * fine (an empty list is valid). `result.index` is the position the removed item had, moved back
61
+ * by one when it was last, so it points at a neighbor; it is -1 when the list is now empty.
62
+ * It does not check the result: it works on a broken list, so users can repair old data.
63
+ * Run validate on result.list to see the problems that are still there.
64
+ */
65
+ export declare function remove(list: ReadonlyArray<Timeframe>, _id: string): Result;
66
+ type TimeframePatch = {
67
+ name?: string | undefined;
68
+ /** `null` removes it, back to the default (1). */
69
+ scrollSensitivity?: number | null | undefined;
70
+ };
71
+ /**
72
+ * Changes only `name` and `scrollSensitivity`; an undefined value keeps the old one. Times change
73
+ * only through add, split, resizeEdge, moveTimeframe and remove. A name that is not a string fails
74
+ * with badItem (validate checks it; the editor crashes on it). Two items with this _id fail with
75
+ * duplicateId.
76
+ */
77
+ export declare function update(list: ReadonlyArray<Timeframe>, _id: string, patch: TimeframePatch, rules: Rules): Result;
78
+ /**
79
+ * A guard for a video length that is a little off (the 1 ms rounding of ms → s → ms). Any timeframe
80
+ * that ends past `rules.durationMs` is cut to end there. It never resets and never makes a timeframe
81
+ * longer: a longer video just has a gap at the end. It drops nothing: an item that starts at or
82
+ * after `durationMs` is a tooShort error, and so is an item that would get under MIN_LENGTH_MS.
83
+ * An empty list comes back as it is. The result is checked like every other write.
84
+ */
85
+ export declare function fitToDuration(list: ReadonlyArray<Timeframe>, rules: Rules): Result;
86
+ export {};
@@ -0,0 +1,13 @@
1
+ export type { Timeframe, TimeframeError, TimeframeErrorCode, TimeframeTiming, NewTimeframe, NewTimeframeId, Result, Rules, } from './types';
2
+ export { DEFAULT_TIMEFRAME_MS, MAX_COUNT, MIN_LENGTH_MS } from './types';
3
+ export { parseList, toMs } from './parse';
4
+ export type { ParsedList } from './parse';
5
+ export { createTimeframeId } from './timeframeId';
6
+ export { validate } from './validate';
7
+ export { add, createInitial, edgeLimits, fitToDuration, moveTimeframe, moveLimits, remove, resizeEdge, split, update, } from './edit';
8
+ export type { Edge } from './edit';
9
+ export { activeAt } from './query';
10
+ export { watchVideoTime } from './watchVideoTime';
11
+ export { useActiveTimeframeIndex } from './useActiveTimeframeIndex';
12
+ export { TimeframeLayer } from './TimeframeLayer';
13
+ export type { TimeframeLayerItem, TimeframeLayerProps } from './TimeframeLayer';
@@ -0,0 +1,26 @@
1
+ import { Timeframe, TimeframeError, NewTimeframeId } from './types';
2
+ /**
3
+ * Video seconds to whole milliseconds, rounded down. A non-finite input gives NaN.
4
+ * The tiny 1e-6 keeps exact ms safe through ms → s → ms: 8.033 * 1000 is 8032.999… in floating point.
5
+ */
6
+ export declare const toMs: (seconds: number) => number;
7
+ export type ParsedList = {
8
+ list: Array<Timeframe>;
9
+ errors: Array<TimeframeError>;
10
+ /**
11
+ * Items that got a new timeframeIdentifier: theirs was missing, or an earlier item already had it
12
+ * (for example an item the editor duplicated). Not an error: write the list back once so the ids
13
+ * are saved. Until then each parse makes different ids.
14
+ */
15
+ addedKeys: Array<{
16
+ _id: string;
17
+ timeframeIdentifier: string;
18
+ }>;
19
+ };
20
+ /**
21
+ * The only way editor data enters the module. It never throws and never checks order, overlap or length (that is validate).
22
+ * `undefined` / `null` (no timeframes saved yet) gives an empty list with no errors.
23
+ */
24
+ export declare function parseList(data: unknown, { newTimeframeId, }?: {
25
+ newTimeframeId?: NewTimeframeId;
26
+ }): ParsedList;
@@ -0,0 +1,7 @@
1
+ import { TimeframeTiming } from './types';
2
+ /**
3
+ * The timeframe showing at `timeMs`: the one with `startMs <= timeMs < endMs`. In a gap, undefined
4
+ * (nothing is shown over the video). At or after `durationMs` (the video ended), the timeframe that
5
+ * ends at the end of the video; if none does, the end is a gap.
6
+ */
7
+ export declare function activeAt<T extends TimeframeTiming>(list: ReadonlyArray<T>, timeMs: number, durationMs: number): T | undefined;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * A new timeframeIdentifier: crypto.randomUUID when it exists, else a small fallback that is
3
+ * unique enough inside one list (time + counter + random).
4
+ */
5
+ export declare function createTimeframeId(): string;
@@ -0,0 +1,64 @@
1
+ /** A timeframe that the editor has saved. */
2
+ export type Timeframe = {
3
+ /** The editor's own id. Not in runtime props, so never use it as a React key. */
4
+ _id: string;
5
+ /** Our own stable id. Saved as a text field; use it as the React key. */
6
+ timeframeIdentifier: string;
7
+ /**
8
+ * Owner-only label ("Title" in the panel); may be ''. Called `name` because the editor's array
9
+ * indicator reads `item.name` (and crashes on undefined).
10
+ */
11
+ name: string;
12
+ /** Integer, inclusive. */
13
+ startMs: number;
14
+ /** Integer, exclusive. */
15
+ endMs: number;
16
+ /** Opaque ref; the editor owns the real container. */
17
+ container?: string;
18
+ /** Stored only; missing = 1. */
19
+ scrollSensitivity?: number;
20
+ };
21
+ /** An item this module asks the editor to create. No _id. */
22
+ export type NewTimeframe = Omit<Timeframe, '_id'>;
23
+ /** Makes a new timeframeIdentifier. Inject one in tests to get fixed ids. */
24
+ export type NewTimeframeId = () => string;
25
+ /** `durationMs` must be a finite, positive whole number. */
26
+ export type Rules = {
27
+ durationMs: number;
28
+ newTimeframeId?: NewTimeframeId;
29
+ };
30
+ /** The only fields `activeAt` needs. */
31
+ export type TimeframeTiming = Pick<NewTimeframe, 'startMs' | 'endMs'>;
32
+ export declare const MIN_LENGTH_MS = 100;
33
+ export declare const MAX_COUNT = 40;
34
+ /**
35
+ * The class on the element that wraps each timeframe's container. The manifest's container
36
+ * `selector` points at it, like Accordion's `.item-content`. The editor needs this selector to find
37
+ * each container. (Saves can still fail with SCHEMA_REFERENCES_NOT_FOUND; that is a server bug.)
38
+ */
39
+ export declare const TIMEFRAME_CONTENT_CLASS = "timeframe-content";
40
+ /** Length of a new timeframe from createInitial and add, when there is room. */
41
+ export declare const DEFAULT_TIMEFRAME_MS = 5000;
42
+ export type TimeframeErrorCode = 'badTime' | 'tooShort' | 'outOfRange' | 'notSorted' | 'overlap' | 'tooMany' | 'notFound' | 'onBoundary' | 'inGap' | 'insideTimeframe' | 'noRoom' | 'badSensitivity' | 'badItem' | 'badKey' | 'duplicateKey' | 'duplicateId';
43
+ export type TimeframeError = {
44
+ code: TimeframeErrorCode;
45
+ /**
46
+ * Position in the list, or -1 for whole-list problems. For a parseList `badItem` it is the
47
+ * position in the raw editor data: that item is not in `parsed.list`, which is also sorted.
48
+ */
49
+ index: number;
50
+ _id?: string;
51
+ };
52
+ export type Result = {
53
+ ok: true;
54
+ list: Array<Timeframe | NewTimeframe>;
55
+ index: number;
56
+ } | {
57
+ ok: false;
58
+ errors: Array<TimeframeError>;
59
+ };
60
+ export declare const timeframeError: (code: TimeframeErrorCode, index: number, _id?: unknown) => TimeframeError;
61
+ /** A video length the rules accept: a positive whole number of ms. */
62
+ export declare const isDuration: (durationMs: number | undefined) => durationMs is number;
63
+ export declare function assertDuration(durationMs: number): void;
64
+ export declare function assertList(list: unknown): void;
@@ -0,0 +1,8 @@
1
+ import { TimeframeTiming } from './types';
2
+ /**
3
+ * The index of the timeframe showing in `video` now. It re-renders only when the index changes.
4
+ * `durationMs` comes from the data. Undefined or invalid gives undefined.
5
+ * Before a video is attached (and on the server), it is the timeframe at time 0.
6
+ * Pass a stable `timeframes` array (memoized): a new array restarts the video listeners.
7
+ */
8
+ export declare function useActiveTimeframeIndex<T extends TimeframeTiming>(timeframes: ReadonlyArray<T>, video: HTMLVideoElement | null, durationMs: number | undefined): number | undefined;
@@ -0,0 +1,17 @@
1
+ import { TimeframeError, NewTimeframe, Rules } from './types';
2
+ type Item = NewTimeframe & {
3
+ _id?: string;
4
+ };
5
+ /**
6
+ * Like validate, but without checking durationMs. For internal use. By default one error per item
7
+ * (the first problem); `all` gives every problem, which the edits need to compare before and after.
8
+ */
9
+ export declare function collectErrors(list: ReadonlyArray<Item>, durationMs: number, { all }?: {
10
+ all?: boolean;
11
+ }): Array<TimeframeError>;
12
+ /**
13
+ * Checks a list: sorted by startMs, no overlap (touching is fine), every timeframe at least
14
+ * MIN_LENGTH_MS and inside `[0, durationMs]`. Gaps and an empty list are valid.
15
+ */
16
+ export declare function validate(list: ReadonlyArray<Item>, rules: Rules): Array<TimeframeError>;
17
+ export {};
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Calls onTimeMs with toMs(video.currentTime) and video.ended whenever either may have changed.
3
+ * `ended` is true when the video is scrubbed to the end, and currentTime may stop a bit before the
4
+ * real end, so a caller that needs "the end" should check `ended`, not the time.
5
+ * Returns stop(), which is safe to call twice.
6
+ */
7
+ export declare function watchVideoTime(video: HTMLVideoElement, onTimeMs: (timeMs: number, ended: boolean) => void): () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/editor-react-components",
3
- "version": "1.2748.0",
3
+ "version": "1.2749.0",
4
4
  "description": "React components for the Wix Editor",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -222,5 +222,5 @@
222
222
  "registry": "https://registry.npmjs.org/",
223
223
  "access": "public"
224
224
  },
225
- "falconPackageHash": "f5b0ee95fa88e0d111bf5af6485d76c7e88ea2863896a437aa511f30"
225
+ "falconPackageHash": "4308638f3d5b885f504d39750fffccea1e3377db04ca7104e417300c"
226
226
  }