@design-edito/tools 0.5.13 → 0.5.15
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/agnostic/colors/index.d.ts +1 -1
- package/agnostic/colors/index.js +1 -1
- package/agnostic/css/index.d.ts +2 -2
- package/agnostic/css/index.js +2 -2
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.d.ts +14 -14
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.js +14 -14
- package/agnostic/html/hyper-json/smart-tags/isolated/index.d.ts +3 -3
- package/agnostic/html/hyper-json/smart-tags/isolated/index.js +3 -3
- package/agnostic/html/index.d.ts +2 -2
- package/agnostic/html/index.js +2 -2
- package/agnostic/index.d.ts +2 -2
- package/agnostic/index.js +2 -2
- package/agnostic/misc/index.d.ts +3 -3
- package/agnostic/misc/index.js +3 -3
- package/agnostic/numbers/index.d.ts +3 -3
- package/agnostic/numbers/index.js +3 -3
- package/agnostic/objects/index.d.ts +3 -3
- package/agnostic/objects/index.js +3 -3
- package/agnostic/optim/index.d.ts +1 -1
- package/agnostic/optim/index.js +1 -1
- package/agnostic/strings/index.d.ts +4 -4
- package/agnostic/strings/index.js +4 -4
- package/agnostic/time/dates/format-date/index.d.ts +19 -4
- package/agnostic/time/dates/format-date/index.js +24 -7
- package/agnostic/time/dates/format-date/index.test.js +20 -7
- package/agnostic/time/dates/format-date/parts.js +4 -4
- package/agnostic/time/dates/format-date/types.d.ts +9 -9
- package/agnostic/time/duration/format-duration/index.d.ts +18 -1
- package/agnostic/time/duration/format-duration/index.js +44 -7
- package/agnostic/time/duration/format-duration/index.test.js +27 -0
- package/agnostic/time/duration/format-duration/types.d.ts +21 -1
- package/agnostic/time/index.d.ts +1 -1
- package/agnostic/time/index.js +1 -1
- package/components/Video/index.controlled.d.ts +12 -0
- package/components/Video/index.controlled.js +8 -3
- package/components/Video/utils.d.ts +0 -29
- package/components/Video/utils.js +0 -51
- package/components/index.d.ts +2 -2
- package/components/index.js +2 -2
- package/node/@aws-s3/storage/directory/index.d.ts +1 -1
- package/node/@aws-s3/storage/directory/index.js +1 -1
- package/node/@aws-s3/storage/file/index.d.ts +1 -1
- package/node/@aws-s3/storage/file/index.js +1 -1
- package/node/@aws-s3/storage/index.d.ts +1 -1
- package/node/@aws-s3/storage/index.js +1 -1
- package/node/@google-cloud/storage/directory/index.d.ts +1 -1
- package/node/@google-cloud/storage/directory/index.js +1 -1
- package/node/@google-cloud/storage/file/index.d.ts +2 -2
- package/node/@google-cloud/storage/file/index.js +2 -2
- package/node/cloud-storage/operations/index.d.ts +3 -3
- package/node/cloud-storage/operations/index.js +3 -3
- package/node/files/index.d.ts +1 -1
- package/node/files/index.js +1 -1
- package/node/ftps/directory/index.d.ts +1 -1
- package/node/ftps/directory/index.js +1 -1
- package/node/ftps/file/index.d.ts +2 -2
- package/node/ftps/file/index.js +2 -2
- package/node/images/transform/operations/index.d.ts +4 -4
- package/node/images/transform/operations/index.js +4 -4
- package/node/sftp/directory/index.d.ts +1 -1
- package/node/sftp/directory/index.js +1 -1
- package/package.json +1 -1
|
@@ -19,14 +19,31 @@ import type { FormatDurationOptions } from './types.js';
|
|
|
19
19
|
* - `m` / `mm` : Minutes
|
|
20
20
|
* - `s` / `ss` : Seconds
|
|
21
21
|
* - `ms` : Milliseconds, padded to three digits
|
|
22
|
+
* - `f` / `ff` : The millisecond part counted in frames, at `options.fps`
|
|
22
23
|
*
|
|
23
24
|
* @param duration - The duration to format, as a {@link Duration} or a number of
|
|
24
25
|
* milliseconds.
|
|
25
26
|
* @param format - The template string containing tokens.
|
|
26
|
-
* @param options - How to handle the remainder
|
|
27
|
+
* @param options - How to handle the remainder, the month/year approximation and
|
|
28
|
+
* the frame rate.
|
|
27
29
|
* @returns Formatted duration string. An unknown token is left untouched, braces
|
|
28
30
|
* included.
|
|
29
31
|
* @see {@link getDurationParts} to reach the same parts as plain values.
|
|
32
|
+
* @see {@link formatDate} — the same template grammar, for a point in time rather
|
|
33
|
+
* than a length of it.
|
|
34
|
+
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* This function and `formatDate` share one grammar: `{{…}}` delimiters, everything
|
|
37
|
+
* outside them literal, the bare token being the plain number and the doubled one
|
|
38
|
+
* that same number padded to two digits, `ms` padded to three, and an unknown token
|
|
39
|
+
* left as written. No token means two different kinds of thing across the two.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* **The template decides the breakdown, so nothing is ever lost for not having been
|
|
43
|
+
* asked for.** `'{{w}}w {{h}}h'` counts hours up to 167 because the week is there and
|
|
44
|
+
* the day is not; `'{{mm}}:{{ss}}'` on an hour-long video reads `62:05` rather than
|
|
45
|
+
* dropping the hour. The single-unit case follows from the same rule: `'{{s}}s'`
|
|
46
|
+
* carries the whole duration.
|
|
30
47
|
*
|
|
31
48
|
* @remarks
|
|
32
49
|
* A negative duration yields negative parts, so every token renders a signed
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { getDurationParts } from './parts.js';
|
|
2
2
|
// Alternation is ordered, and the first branch that fits wins — so the longest
|
|
3
3
|
// tokens come first. `m` ahead of `ms` or `mm` would swallow them.
|
|
4
|
-
const tokenRegexp = /\{\{(YY|MM|ww|dd|hh|mm|ss|ms|Y|M|w|d|h|m|s)\}\}/gv;
|
|
5
|
-
/**
|
|
4
|
+
const tokenRegexp = /\{\{(YY|MM|ww|dd|hh|mm|ss|ms|ff|Y|M|w|d|h|m|s|f)\}\}/gv;
|
|
5
|
+
/**
|
|
6
|
+
* Which tokens read which unit, longest unit first.
|
|
7
|
+
*
|
|
8
|
+
* `f` and `ff` sit under `ms` rather than under a unit of their own: a frame is
|
|
9
|
+
* the millisecond part counted in another base, so a template asking for frames
|
|
10
|
+
* is a template asking the cascade to run down to milliseconds.
|
|
11
|
+
*/
|
|
6
12
|
const unitTokens = [
|
|
7
13
|
['Y', ['Y', 'YY']],
|
|
8
14
|
['M', ['M', 'MM']],
|
|
@@ -11,7 +17,7 @@ const unitTokens = [
|
|
|
11
17
|
['h', ['h', 'hh']],
|
|
12
18
|
['m', ['m', 'mm']],
|
|
13
19
|
['s', ['s', 'ss']],
|
|
14
|
-
['ms', ['ms']]
|
|
20
|
+
['ms', ['ms', 'f', 'ff']]
|
|
15
21
|
];
|
|
16
22
|
function pad(value, length) {
|
|
17
23
|
return `${value}`.padStart(length, '0');
|
|
@@ -36,8 +42,22 @@ const renderers = {
|
|
|
36
42
|
'mm': parts => pad(parts.m, 2),
|
|
37
43
|
's': parts => `${parts.s}`,
|
|
38
44
|
'ss': parts => pad(parts.s, 2),
|
|
39
|
-
'ms': parts => pad(parts.ms, 3)
|
|
45
|
+
'ms': parts => pad(parts.ms, 3),
|
|
46
|
+
'f': (parts, fps) => `${toFrames(parts.ms, fps)}`,
|
|
47
|
+
'ff': (parts, fps) => pad(toFrames(parts.ms, fps), 2)
|
|
40
48
|
};
|
|
49
|
+
/**
|
|
50
|
+
* The millisecond part counted in frames.
|
|
51
|
+
*
|
|
52
|
+
* Truncated rather than rounded: a frame is only reached once it has fully
|
|
53
|
+
* elapsed, so 39 ms at 25 fps is frame `0`, not frame `1`. The sign is carried
|
|
54
|
+
* around the truncation, so a negative part stays negative — the whole function
|
|
55
|
+
* keeps a duration's parts faithful rather than tidying them.
|
|
56
|
+
*/
|
|
57
|
+
function toFrames(ms, fps) {
|
|
58
|
+
const sign = ms < 0 ? -1 : 1;
|
|
59
|
+
return Math.floor(Math.abs(ms) / 1000 * fps) * sign;
|
|
60
|
+
}
|
|
41
61
|
/** The units a template asks for, read off the tokens it actually uses. */
|
|
42
62
|
function unitsInFormat(format) {
|
|
43
63
|
return unitTokens
|
|
@@ -63,14 +83,31 @@ function unitsInFormat(format) {
|
|
|
63
83
|
* - `m` / `mm` : Minutes
|
|
64
84
|
* - `s` / `ss` : Seconds
|
|
65
85
|
* - `ms` : Milliseconds, padded to three digits
|
|
86
|
+
* - `f` / `ff` : The millisecond part counted in frames, at `options.fps`
|
|
66
87
|
*
|
|
67
88
|
* @param duration - The duration to format, as a {@link Duration} or a number of
|
|
68
89
|
* milliseconds.
|
|
69
90
|
* @param format - The template string containing tokens.
|
|
70
|
-
* @param options - How to handle the remainder
|
|
91
|
+
* @param options - How to handle the remainder, the month/year approximation and
|
|
92
|
+
* the frame rate.
|
|
71
93
|
* @returns Formatted duration string. An unknown token is left untouched, braces
|
|
72
94
|
* included.
|
|
73
95
|
* @see {@link getDurationParts} to reach the same parts as plain values.
|
|
96
|
+
* @see {@link formatDate} — the same template grammar, for a point in time rather
|
|
97
|
+
* than a length of it.
|
|
98
|
+
*
|
|
99
|
+
* @remarks
|
|
100
|
+
* This function and `formatDate` share one grammar: `{{…}}` delimiters, everything
|
|
101
|
+
* outside them literal, the bare token being the plain number and the doubled one
|
|
102
|
+
* that same number padded to two digits, `ms` padded to three, and an unknown token
|
|
103
|
+
* left as written. No token means two different kinds of thing across the two.
|
|
104
|
+
*
|
|
105
|
+
* @remarks
|
|
106
|
+
* **The template decides the breakdown, so nothing is ever lost for not having been
|
|
107
|
+
* asked for.** `'{{w}}w {{h}}h'` counts hours up to 167 because the week is there and
|
|
108
|
+
* the day is not; `'{{mm}}:{{ss}}'` on an hour-long video reads `62:05` rather than
|
|
109
|
+
* dropping the hour. The single-unit case follows from the same rule: `'{{s}}s'`
|
|
110
|
+
* carries the whole duration.
|
|
74
111
|
*
|
|
75
112
|
* @remarks
|
|
76
113
|
* A negative duration yields negative parts, so every token renders a signed
|
|
@@ -84,11 +121,11 @@ function unitsInFormat(format) {
|
|
|
84
121
|
* // => "1:02:05"
|
|
85
122
|
*/
|
|
86
123
|
export function formatDuration(duration, format, options = {}) {
|
|
87
|
-
const { floorSmallestUnit = true, useApproximateMonthAndYear = true } = options;
|
|
124
|
+
const { floorSmallestUnit = true, useApproximateMonthAndYear = true, fps = 25 } = options;
|
|
88
125
|
const parts = getDurationParts(duration, {
|
|
89
126
|
units: unitsInFormat(format),
|
|
90
127
|
floorSmallestUnit,
|
|
91
128
|
useApproximateMonthAndYear
|
|
92
129
|
});
|
|
93
|
-
return format.replace(tokenRegexp, (_match, token) => renderers[token](parts));
|
|
130
|
+
return format.replace(tokenRegexp, (_match, token) => renderers[token](parts, fps));
|
|
94
131
|
}
|
|
@@ -53,6 +53,33 @@ describe('formatDuration', () => {
|
|
|
53
53
|
expect(formatDuration(seconds(-90), '{{m}}:{{ss}}')).toBe('-1:-30');
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
|
+
describe('frames', () => {
|
|
57
|
+
it('counts the sub-second remainder in frames, at 25 fps by default', () => {
|
|
58
|
+
expect(formatDuration(3725240, '{{mm}}:{{ss}}.{{ff}}')).toBe('62:05.06');
|
|
59
|
+
expect(formatDuration(3725240, '{{mm}}:{{ss}}.{{f}}')).toBe('62:05.6');
|
|
60
|
+
});
|
|
61
|
+
it('counts in the frame rate it is given', () => {
|
|
62
|
+
expect(formatDuration(3725240, '{{ss}}.{{ff}}', { fps: 50 })).toBe('3725.12');
|
|
63
|
+
});
|
|
64
|
+
// A frame is reached once it has fully elapsed, so the 40th millisecond is
|
|
65
|
+
// where frame 1 starts at 25 fps — not the 39th.
|
|
66
|
+
it('truncates rather than rounds to the frame', () => {
|
|
67
|
+
expect(formatDuration(39, '{{s}}.{{ff}}')).toBe('0.00');
|
|
68
|
+
expect(formatDuration(40, '{{s}}.{{ff}}')).toBe('0.01');
|
|
69
|
+
});
|
|
70
|
+
// Frames are milliseconds in another base, so they pull the cascade down to
|
|
71
|
+
// milliseconds exactly as `{{ms}}` would — without needing `{{ms}}` written.
|
|
72
|
+
it('runs the cascade down to milliseconds without a ms token', () => {
|
|
73
|
+
expect(formatDuration(3725240, '{{ss}}')).toBe('3725');
|
|
74
|
+
expect(formatDuration(3725240, '{{ss}}.{{ff}}')).toBe('3725.06');
|
|
75
|
+
});
|
|
76
|
+
it('puts the whole duration on frames when it is the only token', () => {
|
|
77
|
+
expect(formatDuration(seconds(2), '{{f}}')).toBe('50');
|
|
78
|
+
});
|
|
79
|
+
it('signs a frame count like every other part', () => {
|
|
80
|
+
expect(formatDuration(-240, '{{s}}.{{f}}')).toBe('0.-6');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
56
83
|
});
|
|
57
84
|
describe('getDurationParts', () => {
|
|
58
85
|
describe('breakdown', () => {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export type DurationUnit = 'ms' | 's' | 'm' | 'h' | 'd' | 'w' | 'M' | 'Y';
|
|
6
6
|
/** Every token `formatDuration` substitutes in a template. */
|
|
7
|
-
export type DurationToken = 'Y' | 'YY' | 'M' | 'MM' | 'w' | 'ww' | 'd' | 'dd' | 'h' | 'hh' | 'm' | 'mm' | 's' | 'ss' | 'ms';
|
|
7
|
+
export type DurationToken = 'Y' | 'YY' | 'M' | 'MM' | 'w' | 'ww' | 'd' | 'dd' | 'h' | 'hh' | 'm' | 'mm' | 's' | 'ss' | 'ms' | 'f' | 'ff';
|
|
8
8
|
/** Options for `getDurationParts`. */
|
|
9
9
|
export type GetDurationPartsOptions = {
|
|
10
10
|
/**
|
|
@@ -25,6 +25,16 @@ export type GetDurationPartsOptions = {
|
|
|
25
25
|
* 365.2425 days and a month of exactly a twelfth of it.
|
|
26
26
|
*/
|
|
27
27
|
useApproximateMonthAndYear?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Frame rate the `f` and `ff` tokens count in. Defaults to `25`.
|
|
30
|
+
*
|
|
31
|
+
* Frames are a *rendering* of the millisecond part, not a unit of their own —
|
|
32
|
+
* they never appear in {@link DurationParts}, and a template asking for them
|
|
33
|
+
* asks for milliseconds under another base. So `'{{ss}}.{{ff}}'` reads the
|
|
34
|
+
* sub-second remainder, while `'{{f}}'` alone puts the whole duration on
|
|
35
|
+
* frames, exactly as `'{{ms}}'` alone puts it on milliseconds.
|
|
36
|
+
*/
|
|
37
|
+
fps?: number;
|
|
28
38
|
};
|
|
29
39
|
/**
|
|
30
40
|
* A duration's parts, keyed by unit token.
|
|
@@ -90,4 +100,14 @@ export type FormatDurationOptions = {
|
|
|
90
100
|
* 365.2425 days and a month of exactly a twelfth of it.
|
|
91
101
|
*/
|
|
92
102
|
useApproximateMonthAndYear?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Frame rate the `f` and `ff` tokens count in. Defaults to `25`.
|
|
105
|
+
*
|
|
106
|
+
* Frames are a *rendering* of the millisecond part, not a unit of their own —
|
|
107
|
+
* they never appear in {@link DurationParts}, and a template asking for them
|
|
108
|
+
* asks for milliseconds under another base. So `'{{ss}}.{{ff}}'` reads the
|
|
109
|
+
* sub-second remainder, while `'{{f}}'` alone puts the whole duration on
|
|
110
|
+
* frames, exactly as `'{{ms}}'` alone puts it on milliseconds.
|
|
111
|
+
*/
|
|
112
|
+
fps?: number;
|
|
93
113
|
};
|
package/agnostic/time/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
export * as timeout from './timeout/index.js'
|
|
1
2
|
export * as dates from './dates/index.js'
|
|
2
3
|
export * as duration from './duration/index.js'
|
|
3
|
-
export * as timeout from './timeout/index.js'
|
|
4
4
|
export * as transitions from './transitions/index.js'
|
|
5
5
|
export * as wait from './wait/index.js'
|
package/agnostic/time/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
export * as timeout from './timeout/index.js'
|
|
1
2
|
export * as dates from './dates/index.js'
|
|
2
3
|
export * as duration from './duration/index.js'
|
|
3
|
-
export * as timeout from './timeout/index.js'
|
|
4
4
|
export * as transitions from './transitions/index.js'
|
|
5
5
|
export * as wait from './wait/index.js'
|
|
@@ -85,6 +85,17 @@ type TrackData = {
|
|
|
85
85
|
* fullscreen on its own — pressing Escape, typically — with the new state. This is
|
|
86
86
|
* the signal a parent needs to update its `fullscreen` prop, and it is distinct
|
|
87
87
|
* from `onIsFullscreenChanged`, which merely echoes that prop back once changed.
|
|
88
|
+
* @property timeFormat - How the two clocks are written, as a {@link formatDuration}
|
|
89
|
+
* pattern. Tokens go in `{{…}}` and the rest is literal, so `'{{m}} min {{ss}}'` is a
|
|
90
|
+
* valid answer. Defaults to `'{{mm}}:{{ss}}:{{ms}}'` — milliseconds included, which is
|
|
91
|
+
* what a cutting room wants and almost never what an article does: `'{{mm}}:{{ss}}'` is
|
|
92
|
+
* the usual one. Frames (`{{f}}`, `{{ff}}`) are derived at 25 fps, not configurable
|
|
93
|
+
* here.
|
|
94
|
+
*
|
|
95
|
+
* The pattern decides how the duration is split: the units it names are the units it
|
|
96
|
+
* gets, each taking its whole part and handing the rest down. So `'{{mm}}:{{ss}}'` on
|
|
97
|
+
* an hour-long video reads `62:05` rather than dropping the hour — nothing is ever
|
|
98
|
+
* lost for not having been asked for.
|
|
88
99
|
* @property className - Additional CSS class for the root element.
|
|
89
100
|
* @property children - React content inserted into the <video> tag (fallback, etc).
|
|
90
101
|
*
|
|
@@ -105,6 +116,7 @@ export type Props = PropsWithChildren<WithClassName<{
|
|
|
105
116
|
mute?: boolean;
|
|
106
117
|
playbackRate?: number;
|
|
107
118
|
currentTimeMs?: number;
|
|
119
|
+
timeFormat?: string;
|
|
108
120
|
onPlayButtonClicked?: (e: React.MouseEvent<HTMLButtonElement>, isPlaying: boolean, video: HTMLVideoElement | null) => void;
|
|
109
121
|
onPauseButtonClicked?: (e: React.MouseEvent<HTMLButtonElement>, isPlaying: boolean, video: HTMLVideoElement | null) => void;
|
|
110
122
|
onLoudButtonClicked?: (e: React.MouseEvent<HTMLButtonElement>, isLoud: boolean, video: HTMLVideoElement | null) => void;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo, useRef, useState, useCallback, useEffect } from 'react';
|
|
3
3
|
import { clss } from '../../agnostic/css/clss/index.js';
|
|
4
|
+
import { formatDuration } from '../../agnostic/time/duration/format-duration/index.js';
|
|
4
5
|
import { mergeClassNames, useChangeDispatch } from '../utils/index.js';
|
|
5
6
|
import cssModule from './styles.module.css';
|
|
6
7
|
import { video as publicClassName } from '../public-classnames.js';
|
|
7
8
|
import { Subtitles } from '../Subtitles/index.js';
|
|
8
|
-
import { forceExitFullscreen, forceFullscreen, forceLoud, forceMute, forcePause, forcePlay, forcePlaybackRate, forceVolume,
|
|
9
|
+
import { forceExitFullscreen, forceFullscreen, forceLoud, forceMute, forcePause, forcePlay, forcePlaybackRate, forceVolume, getTimelineClickProgress, msToSeconds, secondsToMs } from './utils.js';
|
|
9
10
|
/**
|
|
10
11
|
* Full-featured video player component. Wraps a native `<video>` element with
|
|
11
12
|
* playback controls, volume, playback rate, a timeline, optional subtitles
|
|
@@ -49,7 +50,11 @@ import { forceExitFullscreen, forceFullscreen, forceLoud, forceMute, forcePause,
|
|
|
49
50
|
* @returns A `<figure>` element containing the video, its controls, optional
|
|
50
51
|
* subtitles.
|
|
51
52
|
*/
|
|
52
|
-
export const ControlledVideo = ({ sources, tracks, subtitles, playBtnContent, pauseBtnContent, loudBtnContent, muteBtnContent, fullscreenBtnContent, play, fullscreen, mute, muted, volume = 1, playbackRate = 1, currentTimeMs: givenCurrentTimeMs,
|
|
53
|
+
export const ControlledVideo = ({ sources, tracks, subtitles, playBtnContent, pauseBtnContent, loudBtnContent, muteBtnContent, fullscreenBtnContent, play, fullscreen, mute, muted, volume = 1, playbackRate = 1, currentTimeMs: givenCurrentTimeMs,
|
|
54
|
+
// Milliseconds by default, which is what this component has always rendered — a
|
|
55
|
+
// default that changes under a consumer is a change nobody asked for. An article
|
|
56
|
+
// usually wants `'{{mm}}:{{ss}}'` and says so.
|
|
57
|
+
timeFormat = '{{mm}}:{{ss}}:{{ms}}', onPlayButtonClicked, onPauseButtonClicked, onLoudButtonClicked, onMuteButtonClicked, onVolumeRangeChanged, onRateRangeChanged, onFullscreenButtonClicked, onTimelineClicked, onIsPlayingChanged, onIsFullscreenChanged, onIsLoudChanged, onIsEndedChanged, onVolumeChanged, onPlaybackRateChanged, onCurrentTimeMsChanged, onFullscreenChange, children, className, ...intrinsicVideoAttributes }) => {
|
|
53
58
|
const videoRef = useRef(null);
|
|
54
59
|
const [totalTime, setTotalTime] = useState(0);
|
|
55
60
|
const totalTimeMs = useMemo(() => secondsToMs(totalTime), [totalTime]);
|
|
@@ -302,5 +307,5 @@ export const ControlledVideo = ({ sources, tracks, subtitles, playBtnContent, pa
|
|
|
302
307
|
? _jsx("source", { src: source }, index)
|
|
303
308
|
: _jsx("source", { src: source.src, type: source.type }, index)), parsedTracks.map((track, index) => typeof track === 'string'
|
|
304
309
|
? _jsx("track", { src: track }, index)
|
|
305
|
-
: _jsx("track", { src: track.src, kind: track.kind, srcLang: track.srclang, label: track.label, default: track.default }, index)), children] }), _jsxs("div", { className: videoControlsClss, children: [_jsx("button", { className: playBtnClss, onClick: handlePlayButtonClick, children: playBtnContent }), _jsx("button", { className: pauseBtnClss, onClick: handlePauseButtonClick, children: pauseBtnContent }), _jsx("button", { className: loudBtnClss, onClick: handleLoudButtonClick, children: loudBtnContent }), _jsx("button", { className: muteBtnClss, onClick: handleMuteButtonClick, children: muteBtnContent }), _jsx("input", { type: 'range', className: volumeRangeClss, value: volumePercent, onChange: handleVolumeRangeChange, min: 0, max: 100, step: 1 }), _jsx("span", { className: volumePcntClss, children: Math.round(volumePercent) }), _jsx("button", { className: fullscreenBtnClss, onClick: handleFullscreenButtonClick, children: fullscreenBtnContent }), _jsx("input", { type: 'range', className: playbackRateRangeClss, value: playbackRate, onChange: handleRateRangeChange, min: 0.25, max: 4, step: 0.25 }), _jsx("span", { className: playbackRateClss, children: playbackRate })] }), _jsxs("div", { className: timeControlsClss, children: [_jsx("span", { className: currentTimeClss, children:
|
|
310
|
+
: _jsx("track", { src: track.src, kind: track.kind, srcLang: track.srclang, label: track.label, default: track.default }, index)), children] }), _jsxs("div", { className: videoControlsClss, children: [_jsx("button", { className: playBtnClss, onClick: handlePlayButtonClick, children: playBtnContent }), _jsx("button", { className: pauseBtnClss, onClick: handlePauseButtonClick, children: pauseBtnContent }), _jsx("button", { className: loudBtnClss, onClick: handleLoudButtonClick, children: loudBtnContent }), _jsx("button", { className: muteBtnClss, onClick: handleMuteButtonClick, children: muteBtnContent }), _jsx("input", { type: 'range', className: volumeRangeClss, value: volumePercent, onChange: handleVolumeRangeChange, min: 0, max: 100, step: 1 }), _jsx("span", { className: volumePcntClss, children: Math.round(volumePercent) }), _jsx("button", { className: fullscreenBtnClss, onClick: handleFullscreenButtonClick, children: fullscreenBtnContent }), _jsx("input", { type: 'range', className: playbackRateRangeClss, value: playbackRate, onChange: handleRateRangeChange, min: 0.25, max: 4, step: 0.25 }), _jsx("span", { className: playbackRateClss, children: playbackRate })] }), _jsxs("div", { className: timeControlsClss, children: [_jsx("span", { className: currentTimeClss, children: formatDuration(currentTimeMs, timeFormat) }), _jsx("span", { className: totalTimeClss, children: formatDuration(totalTimeMs, timeFormat) }), _jsx("div", { className: timelineClss, onClick: handleTimelineClick })] }), subtitles !== undefined && _jsx(Subtitles, { ...subtitles, timecodeMs: currentTimeMs, isEnded: isEnded })] });
|
|
306
311
|
};
|
|
@@ -20,35 +20,6 @@ export declare const forceFullscreen: (video: HTMLVideoElement | null) => Promis
|
|
|
20
20
|
export declare const forceExitFullscreen: (video: HTMLVideoElement | null) => Promise<boolean>;
|
|
21
21
|
export declare function secondsToMs(seconds: number): number;
|
|
22
22
|
export declare function msToSeconds(ms: number): number;
|
|
23
|
-
/**
|
|
24
|
-
* Renders a duration into a caller-defined pattern.
|
|
25
|
-
*
|
|
26
|
-
* The pattern is a free-form string in which the following tokens are replaced,
|
|
27
|
-
* longest first, so that `mm` is consumed before `m`:
|
|
28
|
-
*
|
|
29
|
-
* - `hh`, `mm`, `ss` — hours, minutes and seconds, zero-padded to two digits.
|
|
30
|
-
* - `ms` — the remaining milliseconds, zero-padded to three digits.
|
|
31
|
-
* - `frame` — the remaining milliseconds expressed in frames, zero-padded to two
|
|
32
|
-
* digits.
|
|
33
|
-
* - `h`, `m`, `s`, `f` — the same four values, unpadded.
|
|
34
|
-
*
|
|
35
|
-
* @param ms - The duration, in milliseconds.
|
|
36
|
-
* @param format - The pattern to fill, e.g. `'mm:ss:ms'`.
|
|
37
|
-
* @param fps - Frame rate used to derive the `frame` and `f` tokens. Defaults to `25`.
|
|
38
|
-
* @returns The formatted duration.
|
|
39
|
-
*
|
|
40
|
-
* @remarks
|
|
41
|
-
* Every field is a remainder of the one above it, never a total: at one hour and
|
|
42
|
-
* a half, `mm` is `30`, not `90`. A pattern that omits `hh` therefore loses the
|
|
43
|
-
* hours rather than folding them into the minutes.
|
|
44
|
-
*
|
|
45
|
-
* Since `h`, `m`, `s` and `f` are tokens on their own, **every** occurrence of
|
|
46
|
-
* those letters is substituted, wherever it sits: `'mm min ss'` renders as
|
|
47
|
-
* `'01 1in 01'`. Separate the fields with punctuation. This is what
|
|
48
|
-
* `agnostic/time/dates/format-date` avoids by delimiting its tokens with
|
|
49
|
-
* `{{…}}` — worth aligning on the day this one is made public.
|
|
50
|
-
*/
|
|
51
|
-
export declare function formatTime(ms: number, format: string, fps?: number): string;
|
|
52
23
|
/**
|
|
53
24
|
* Where along the timeline a click landed.
|
|
54
25
|
*
|
|
@@ -107,57 +107,6 @@ export function secondsToMs(seconds) {
|
|
|
107
107
|
export function msToSeconds(ms) {
|
|
108
108
|
return ms / 1000;
|
|
109
109
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Renders a duration into a caller-defined pattern.
|
|
112
|
-
*
|
|
113
|
-
* The pattern is a free-form string in which the following tokens are replaced,
|
|
114
|
-
* longest first, so that `mm` is consumed before `m`:
|
|
115
|
-
*
|
|
116
|
-
* - `hh`, `mm`, `ss` — hours, minutes and seconds, zero-padded to two digits.
|
|
117
|
-
* - `ms` — the remaining milliseconds, zero-padded to three digits.
|
|
118
|
-
* - `frame` — the remaining milliseconds expressed in frames, zero-padded to two
|
|
119
|
-
* digits.
|
|
120
|
-
* - `h`, `m`, `s`, `f` — the same four values, unpadded.
|
|
121
|
-
*
|
|
122
|
-
* @param ms - The duration, in milliseconds.
|
|
123
|
-
* @param format - The pattern to fill, e.g. `'mm:ss:ms'`.
|
|
124
|
-
* @param fps - Frame rate used to derive the `frame` and `f` tokens. Defaults to `25`.
|
|
125
|
-
* @returns The formatted duration.
|
|
126
|
-
*
|
|
127
|
-
* @remarks
|
|
128
|
-
* Every field is a remainder of the one above it, never a total: at one hour and
|
|
129
|
-
* a half, `mm` is `30`, not `90`. A pattern that omits `hh` therefore loses the
|
|
130
|
-
* hours rather than folding them into the minutes.
|
|
131
|
-
*
|
|
132
|
-
* Since `h`, `m`, `s` and `f` are tokens on their own, **every** occurrence of
|
|
133
|
-
* those letters is substituted, wherever it sits: `'mm min ss'` renders as
|
|
134
|
-
* `'01 1in 01'`. Separate the fields with punctuation. This is what
|
|
135
|
-
* `agnostic/time/dates/format-date` avoids by delimiting its tokens with
|
|
136
|
-
* `{{…}}` — worth aligning on the day this one is made public.
|
|
137
|
-
*/
|
|
138
|
-
export function formatTime(ms, format, fps = 25) {
|
|
139
|
-
const totalSeconds = Math.floor(ms / 1000);
|
|
140
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
141
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
142
|
-
const seconds = Math.floor(totalSeconds % 60);
|
|
143
|
-
const frames = Math.floor(((ms % 1000) / 1000) * fps);
|
|
144
|
-
const msRest = Math.floor(ms % 1000);
|
|
145
|
-
const tokens = {
|
|
146
|
-
hh: String(hours).padStart(2, '0'),
|
|
147
|
-
mm: String(minutes).padStart(2, '0'),
|
|
148
|
-
ss: String(seconds).padStart(2, '0'),
|
|
149
|
-
frame: String(frames).padStart(2, '0'),
|
|
150
|
-
ms: String(msRest).padStart(3, '0'),
|
|
151
|
-
h: hours,
|
|
152
|
-
m: minutes,
|
|
153
|
-
s: seconds,
|
|
154
|
-
f: frames
|
|
155
|
-
};
|
|
156
|
-
return Object
|
|
157
|
-
.keys(tokens)
|
|
158
|
-
.sort((a, b) => b.length - a.length)
|
|
159
|
-
.reduce((acc, t) => acc.replace(new RegExp(t, 'gv'), String(tokens[t])), format);
|
|
160
|
-
}
|
|
161
110
|
/**
|
|
162
111
|
* Where along the timeline a click landed.
|
|
163
112
|
*
|
package/components/index.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export * as gallery from './Gallery/index.js'
|
|
|
8
8
|
export * as iframe from './Iframe/index.js'
|
|
9
9
|
export * as image from './Image/index.js'
|
|
10
10
|
export * as input from './Input/index.js'
|
|
11
|
-
export * as intersectionObserver from './IntersectionObserver/index.js'
|
|
12
11
|
export * as jsonEditor from './JsonEditor/index.js'
|
|
12
|
+
export * as intersectionObserver from './IntersectionObserver/index.js'
|
|
13
13
|
export * as lightbox from './Lightbox/index.js'
|
|
14
14
|
export * as listLoader from './ListLoader/index.js'
|
|
15
15
|
export * as overlayer from './Overlayer/index.js'
|
|
@@ -17,8 +17,8 @@ export * as paginator from './Paginator/index.js'
|
|
|
17
17
|
export * as resizeObserver from './ResizeObserver/index.js'
|
|
18
18
|
export * as scrllgngn from './Scrllgngn/index.js'
|
|
19
19
|
export * as scrollListener from './ScrollListener/index.js'
|
|
20
|
-
export * as select from './Select/index.js'
|
|
21
20
|
export * as sequencer from './Sequencer/index.js'
|
|
21
|
+
export * as select from './Select/index.js'
|
|
22
22
|
export * as shadowRoot from './ShadowRoot/index.js'
|
|
23
23
|
export * as subtitles from './Subtitles/index.js'
|
|
24
24
|
export * as textarea from './Textarea/index.js'
|
package/components/index.js
CHANGED
|
@@ -8,8 +8,8 @@ export * as gallery from './Gallery/index.js'
|
|
|
8
8
|
export * as iframe from './Iframe/index.js'
|
|
9
9
|
export * as image from './Image/index.js'
|
|
10
10
|
export * as input from './Input/index.js'
|
|
11
|
-
export * as intersectionObserver from './IntersectionObserver/index.js'
|
|
12
11
|
export * as jsonEditor from './JsonEditor/index.js'
|
|
12
|
+
export * as intersectionObserver from './IntersectionObserver/index.js'
|
|
13
13
|
export * as lightbox from './Lightbox/index.js'
|
|
14
14
|
export * as listLoader from './ListLoader/index.js'
|
|
15
15
|
export * as overlayer from './Overlayer/index.js'
|
|
@@ -17,8 +17,8 @@ export * as paginator from './Paginator/index.js'
|
|
|
17
17
|
export * as resizeObserver from './ResizeObserver/index.js'
|
|
18
18
|
export * as scrllgngn from './Scrllgngn/index.js'
|
|
19
19
|
export * as scrollListener from './ScrollListener/index.js'
|
|
20
|
-
export * as select from './Select/index.js'
|
|
21
20
|
export * as sequencer from './Sequencer/index.js'
|
|
21
|
+
export * as select from './Select/index.js'
|
|
22
22
|
export * as shadowRoot from './ShadowRoot/index.js'
|
|
23
23
|
export * as subtitles from './Subtitles/index.js'
|
|
24
24
|
export * as textarea from './Textarea/index.js'
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export * as copy from './copy/index.js'
|
|
2
2
|
export * as download from './download/index.js'
|
|
3
|
-
export * as exists from './exists/index.js'
|
|
4
3
|
export * as generateSignedUrl from './generate-signed-url/index.js'
|
|
4
|
+
export * as exists from './exists/index.js'
|
|
5
5
|
export * as getPermissions from './get-permissions/index.js'
|
|
6
6
|
export * as getMetadata from './get-metadata/index.js'
|
|
7
|
-
export * as move from './move/index.js'
|
|
8
7
|
export * as remove from './remove/index.js'
|
|
8
|
+
export * as move from './move/index.js'
|
|
9
9
|
export * as revokeSignedUrls from './revoke-signed-urls/index.js'
|
|
10
10
|
export * as stat from './stat/index.js'
|
|
11
11
|
export * as updateMetadata from './update-metadata/index.js'
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export * as copy from './copy/index.js'
|
|
2
2
|
export * as download from './download/index.js'
|
|
3
|
-
export * as exists from './exists/index.js'
|
|
4
3
|
export * as generateSignedUrl from './generate-signed-url/index.js'
|
|
4
|
+
export * as exists from './exists/index.js'
|
|
5
5
|
export * as getPermissions from './get-permissions/index.js'
|
|
6
6
|
export * as getMetadata from './get-metadata/index.js'
|
|
7
|
-
export * as move from './move/index.js'
|
|
8
7
|
export * as remove from './remove/index.js'
|
|
8
|
+
export * as move from './move/index.js'
|
|
9
9
|
export * as revokeSignedUrls from './revoke-signed-urls/index.js'
|
|
10
10
|
export * as stat from './stat/index.js'
|
|
11
11
|
export * as updateMetadata from './update-metadata/index.js'
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export * as copyDir from './copy-dir/index.js'
|
|
2
|
-
export * as downloadFile from './download-file/index.js'
|
|
3
2
|
export * as copyFile from './copy-file/index.js'
|
|
3
|
+
export * as downloadFile from './download-file/index.js'
|
|
4
4
|
export * as existsFile from './exists-file/index.js'
|
|
5
|
-
export * as listDir from './list-dir/index.js'
|
|
6
5
|
export * as moveDir from './move-dir/index.js'
|
|
6
|
+
export * as listDir from './list-dir/index.js'
|
|
7
7
|
export * as moveFile from './move-file/index.js'
|
|
8
8
|
export * as removeDir from './remove-dir/index.js'
|
|
9
|
-
export * as removeFile from './remove-file/index.js'
|
|
10
9
|
export * as statFile from './stat-file/index.js'
|
|
11
10
|
export * as uploadFile from './upload-file/index.js'
|
|
11
|
+
export * as removeFile from './remove-file/index.js'
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export * as copyDir from './copy-dir/index.js'
|
|
2
|
-
export * as downloadFile from './download-file/index.js'
|
|
3
2
|
export * as copyFile from './copy-file/index.js'
|
|
3
|
+
export * as downloadFile from './download-file/index.js'
|
|
4
4
|
export * as existsFile from './exists-file/index.js'
|
|
5
|
-
export * as listDir from './list-dir/index.js'
|
|
6
5
|
export * as moveDir from './move-dir/index.js'
|
|
6
|
+
export * as listDir from './list-dir/index.js'
|
|
7
7
|
export * as moveFile from './move-file/index.js'
|
|
8
8
|
export * as removeDir from './remove-dir/index.js'
|
|
9
|
-
export * as removeFile from './remove-file/index.js'
|
|
10
9
|
export * as statFile from './stat-file/index.js'
|
|
11
10
|
export * as uploadFile from './upload-file/index.js'
|
|
11
|
+
export * as removeFile from './remove-file/index.js'
|
package/node/files/index.d.ts
CHANGED
package/node/files/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * as copy from './copy/index.js'
|
|
2
1
|
export * as download from './download/index.js'
|
|
2
|
+
export * as copy from './copy/index.js'
|
|
3
3
|
export * as exists from './exists/index.js'
|
|
4
|
-
export * as move from './move/index.js'
|
|
5
4
|
export * as remove from './remove/index.js'
|
|
6
5
|
export * as stat from './stat/index.js'
|
|
6
|
+
export * as move from './move/index.js'
|
|
7
7
|
export * as upload from './upload/index.js'
|
package/node/ftps/file/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * as copy from './copy/index.js'
|
|
2
1
|
export * as download from './download/index.js'
|
|
2
|
+
export * as copy from './copy/index.js'
|
|
3
3
|
export * as exists from './exists/index.js'
|
|
4
|
-
export * as move from './move/index.js'
|
|
5
4
|
export * as remove from './remove/index.js'
|
|
6
5
|
export * as stat from './stat/index.js'
|
|
6
|
+
export * as move from './move/index.js'
|
|
7
7
|
export * as upload from './upload/index.js'
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export * as blur from './blur/index.js'
|
|
2
|
-
export * as brighten from './brighten/index.js'
|
|
3
2
|
export * as extend from './extend/index.js'
|
|
4
3
|
export * as extract from './extract/index.js'
|
|
4
|
+
export * as brighten from './brighten/index.js'
|
|
5
5
|
export * as flatten from './flatten/index.js'
|
|
6
6
|
export * as flip from './flip/index.js'
|
|
7
7
|
export * as flop from './flop/index.js'
|
|
8
|
-
export * as hue from './hue/index.js'
|
|
9
8
|
export * as level from './level/index.js'
|
|
10
|
-
export * as normalize from './normalize/index.js'
|
|
11
9
|
export * as lighten from './lighten/index.js'
|
|
10
|
+
export * as hue from './hue/index.js'
|
|
12
11
|
export * as overlay from './overlay/index.js'
|
|
12
|
+
export * as normalize from './normalize/index.js'
|
|
13
13
|
export * as resize from './resize/index.js'
|
|
14
|
-
export * as rotate from './rotate/index.js'
|
|
15
14
|
export * as saturate from './saturate/index.js'
|
|
15
|
+
export * as rotate from './rotate/index.js'
|