@design-edito/tools 0.5.14 → 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/arrays/index.d.ts +2 -2
- package/agnostic/arrays/index.js +2 -2
- 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/errors/index.d.ts +1 -1
- package/agnostic/errors/index.js +1 -1
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.d.ts +12 -12
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.js +12 -12
- package/agnostic/html/hyper-json/smart-tags/isolated/index.d.ts +4 -4
- package/agnostic/html/hyper-json/smart-tags/isolated/index.js +4 -4
- package/agnostic/html/index.d.ts +1 -1
- package/agnostic/html/index.js +1 -1
- package/agnostic/index.d.ts +2 -2
- package/agnostic/index.js +2 -2
- package/agnostic/misc/index.d.ts +5 -5
- package/agnostic/misc/index.js +5 -5
- package/agnostic/numbers/index.d.ts +1 -1
- package/agnostic/numbers/index.js +1 -1
- package/agnostic/objects/index.d.ts +1 -1
- package/agnostic/objects/index.js +1 -1
- package/agnostic/optim/index.d.ts +1 -1
- package/agnostic/optim/index.js +1 -1
- package/agnostic/random/index.d.ts +1 -1
- package/agnostic/random/index.js +1 -1
- package/agnostic/strings/index.d.ts +3 -3
- package/agnostic/strings/index.js +3 -3
- package/agnostic/subtitles/index.d.ts +1 -1
- package/agnostic/subtitles/index.js +1 -1
- 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 +2 -2
- package/agnostic/time/index.js +2 -2
- package/components/Video/index.controlled.d.ts +7 -2
- package/components/Video/index.controlled.js +3 -2
- package/components/Video/utils.d.ts +0 -31
- package/components/Video/utils.js +0 -58
- 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 +2 -2
- package/node/@aws-s3/storage/file/index.js +2 -2
- package/node/@aws-s3/storage/index.d.ts +1 -1
- package/node/@aws-s3/storage/index.js +1 -1
- package/node/@google-cloud/storage/file/index.d.ts +3 -3
- package/node/@google-cloud/storage/file/index.js +3 -3
- package/node/cloud-storage/operations/index.d.ts +3 -3
- package/node/cloud-storage/operations/index.js +3 -3
- package/node/encryption/@aes-256-gcm/index.d.ts +1 -1
- package/node/encryption/@aes-256-gcm/index.js +1 -1
- 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/index.d.ts +1 -1
- package/node/index.js +1 -1
- package/node/process/index.d.ts +1 -1
- package/node/process/index.js +1 -1
- package/node/sftp/directory/index.d.ts +1 -1
- package/node/sftp/directory/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/** Every token `formatDate` substitutes in a template. */
|
|
2
|
-
export type DateToken = 'D' | 'DD' | 'd' | 'dd' | 'M' | 'MM' | 'MMM' | 'MMMM' | 'YY' | 'YYYY' | 'H' | 'HH' | 'h' | 'hh' | 'm' | 'mm' | 's' | 'ss' | 'ms' | 'A' | 'a' | 'th';
|
|
2
|
+
export type DateToken = 'D' | 'DD' | 'd' | 'dd' | 'ddd' | 'dddd' | 'M' | 'MM' | 'MMM' | 'MMMM' | 'YY' | 'YYYY' | 'H' | 'HH' | 'h' | 'hh' | 'm' | 'mm' | 's' | 'ss' | 'ms' | 'A' | 'a' | 'th';
|
|
3
3
|
/**
|
|
4
4
|
* A date's parts, keyed by unit token.
|
|
5
5
|
*
|
|
6
6
|
* Quantities are **numbers** — a day of month is `1`, not `'01'`. Padding and
|
|
7
7
|
* truncation are rendering concerns and belong to `formatDate`, which is why the
|
|
8
|
-
* `DD`, `MM`, `YY`, `HH`, `hh`, `mm` and `ss` tokens have no entry
|
|
9
|
-
* render the same quantity as
|
|
10
|
-
* text rather than a quantity stay strings.
|
|
8
|
+
* `d`, `dd`, `DD`, `MM`, `YY`, `HH`, `hh`, `mm` and `ss` tokens have no entry
|
|
9
|
+
* here: they render the same quantity as the bare token they double. The parts
|
|
10
|
+
* that are localised text rather than a quantity stay strings.
|
|
11
11
|
*/
|
|
12
12
|
export type DateTokenParts = {
|
|
13
|
-
/** Day of month, 1–31. */
|
|
13
|
+
/** Day of month, 1–31. Rendered by `D`, `DD`, `d` and `dd` alike. */
|
|
14
14
|
D: number;
|
|
15
15
|
/** Short weekday name, localised. */
|
|
16
|
-
|
|
16
|
+
ddd: string;
|
|
17
17
|
/** Full weekday name, localised. */
|
|
18
|
-
|
|
18
|
+
dddd: string;
|
|
19
19
|
/** Month number, 1–12 — January is `1`, not `0`. */
|
|
20
20
|
M: number;
|
|
21
21
|
/** Short month name, localised. */
|
|
@@ -51,9 +51,9 @@ export type DateTokenParts = {
|
|
|
51
51
|
export type NamedDateParts = {
|
|
52
52
|
/** {@link DateTokenParts.D} */
|
|
53
53
|
dayOfMonth: number;
|
|
54
|
-
/** {@link DateTokenParts.
|
|
54
|
+
/** {@link DateTokenParts.ddd} */
|
|
55
55
|
shortWeekdayName: string;
|
|
56
|
-
/** {@link DateTokenParts.
|
|
56
|
+
/** {@link DateTokenParts.dddd} */
|
|
57
57
|
fullWeekdayName: string;
|
|
58
58
|
/** {@link DateTokenParts.M} */
|
|
59
59
|
monthNumber: number;
|
|
@@ -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
|
-
export * as wait from './wait/index.js'
|
|
5
4
|
export * as transitions from './transitions/index.js'
|
|
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
|
-
export * as wait from './wait/index.js'
|
|
5
4
|
export * as transitions from './transitions/index.js'
|
|
5
|
+
export * as wait from './wait/index.js'
|
|
@@ -85,12 +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
|
|
88
|
+
* @property timeFormat - How the two clocks are written, as a {@link formatDuration}
|
|
89
89
|
* pattern. Tokens go in `{{…}}` and the rest is literal, so `'{{m}} min {{ss}}'` is a
|
|
90
90
|
* valid answer. Defaults to `'{{mm}}:{{ss}}:{{ms}}'` — milliseconds included, which is
|
|
91
91
|
* what a cutting room wants and almost never what an article does: `'{{mm}}:{{ss}}'` is
|
|
92
|
-
* the usual one. Frames (`{{
|
|
92
|
+
* the usual one. Frames (`{{f}}`, `{{ff}}`) are derived at 25 fps, not configurable
|
|
93
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.
|
|
94
99
|
* @property className - Additional CSS class for the root element.
|
|
95
100
|
* @property children - React content inserted into the <video> tag (fallback, etc).
|
|
96
101
|
*
|
|
@@ -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
|
|
@@ -306,5 +307,5 @@ timeFormat = '{{mm}}:{{ss}}:{{ms}}', onPlayButtonClicked, onPauseButtonClicked,
|
|
|
306
307
|
? _jsx("source", { src: source }, index)
|
|
307
308
|
: _jsx("source", { src: source.src, type: source.type }, index)), parsedTracks.map((track, index) => typeof track === 'string'
|
|
308
309
|
? _jsx("track", { src: track }, index)
|
|
309
|
-
: _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 })] });
|
|
310
311
|
};
|
|
@@ -20,37 +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
|
-
/** The fields {@link formatTime} knows how to render. */
|
|
24
|
-
export type TimeToken = 'hh' | 'mm' | 'ss' | 'ms' | 'frame' | 'h' | 'm' | 's' | 'f';
|
|
25
|
-
/**
|
|
26
|
-
* Renders a duration into a caller-defined pattern.
|
|
27
|
-
*
|
|
28
|
-
* Tokens are wrapped in `{{…}}` and everything outside them is literal, so a pattern
|
|
29
|
-
* may carry words: `'{{m}} min {{ss}}'` renders as `'1 min 05'`.
|
|
30
|
-
*
|
|
31
|
-
* - `{{hh}}`, `{{mm}}`, `{{ss}}` — hours, minutes and seconds, zero-padded to two digits.
|
|
32
|
-
* - `{{ms}}` — the remaining milliseconds, zero-padded to three digits.
|
|
33
|
-
* - `{{frame}}` — those milliseconds expressed in frames, zero-padded to two digits.
|
|
34
|
-
* - `{{h}}`, `{{m}}`, `{{s}}`, `{{f}}` — the same four values, unpadded.
|
|
35
|
-
*
|
|
36
|
-
* @param ms - The duration, in milliseconds.
|
|
37
|
-
* @param format - The pattern to fill, e.g. `'{{mm}}:{{ss}}'`.
|
|
38
|
-
* @param fps - Frame rate used to derive the `frame` and `f` tokens. Defaults to `25`.
|
|
39
|
-
* @returns The formatted duration. An unknown token is left as written, braces
|
|
40
|
-
* included, rather than silently blanked — a typo has to be visible.
|
|
41
|
-
*
|
|
42
|
-
* @remarks
|
|
43
|
-
* Every field is a remainder of the one above it, never a total: at one hour and a half,
|
|
44
|
-
* `{{mm}}` is `30`, not `90`. A pattern that omits `{{hh}}` therefore loses the hours
|
|
45
|
-
* rather than folding them into the minutes.
|
|
46
|
-
*
|
|
47
|
-
* **The delimiters are what make the pattern free-form.** Until they existed, `h`, `m`,
|
|
48
|
-
* `s` and `f` were tokens on their own and every occurrence of those letters was
|
|
49
|
-
* substituted wherever it sat — `'mm min ss'` rendered as `'01 1in 01'`, so a pattern
|
|
50
|
-
* could only ever separate its fields with punctuation. That is why the format could not
|
|
51
|
-
* be exposed as a prop: doing so would have published the trap.
|
|
52
|
-
*/
|
|
53
|
-
export declare function formatTime(ms: number, format: string, fps?: number): string;
|
|
54
23
|
/**
|
|
55
24
|
* Where along the timeline a click landed.
|
|
56
25
|
*
|
|
@@ -107,64 +107,6 @@ export function secondsToMs(seconds) {
|
|
|
107
107
|
export function msToSeconds(ms) {
|
|
108
108
|
return ms / 1000;
|
|
109
109
|
}
|
|
110
|
-
// Alternation is ordered and the first branch that fits wins, so the longest tokens
|
|
111
|
-
// come first — the same regexp shape, and the same reason, as
|
|
112
|
-
// `agnostic/time/dates/format-date`.
|
|
113
|
-
const timeTokenRegexp = /\{\{(frame|hh|mm|ss|ms|h|m|s|f)\}\}/gv;
|
|
114
|
-
/**
|
|
115
|
-
* Renders a duration into a caller-defined pattern.
|
|
116
|
-
*
|
|
117
|
-
* Tokens are wrapped in `{{…}}` and everything outside them is literal, so a pattern
|
|
118
|
-
* may carry words: `'{{m}} min {{ss}}'` renders as `'1 min 05'`.
|
|
119
|
-
*
|
|
120
|
-
* - `{{hh}}`, `{{mm}}`, `{{ss}}` — hours, minutes and seconds, zero-padded to two digits.
|
|
121
|
-
* - `{{ms}}` — the remaining milliseconds, zero-padded to three digits.
|
|
122
|
-
* - `{{frame}}` — those milliseconds expressed in frames, zero-padded to two digits.
|
|
123
|
-
* - `{{h}}`, `{{m}}`, `{{s}}`, `{{f}}` — the same four values, unpadded.
|
|
124
|
-
*
|
|
125
|
-
* @param ms - The duration, in milliseconds.
|
|
126
|
-
* @param format - The pattern to fill, e.g. `'{{mm}}:{{ss}}'`.
|
|
127
|
-
* @param fps - Frame rate used to derive the `frame` and `f` tokens. Defaults to `25`.
|
|
128
|
-
* @returns The formatted duration. An unknown token is left as written, braces
|
|
129
|
-
* included, rather than silently blanked — a typo has to be visible.
|
|
130
|
-
*
|
|
131
|
-
* @remarks
|
|
132
|
-
* Every field is a remainder of the one above it, never a total: at one hour and a half,
|
|
133
|
-
* `{{mm}}` is `30`, not `90`. A pattern that omits `{{hh}}` therefore loses the hours
|
|
134
|
-
* rather than folding them into the minutes.
|
|
135
|
-
*
|
|
136
|
-
* **The delimiters are what make the pattern free-form.** Until they existed, `h`, `m`,
|
|
137
|
-
* `s` and `f` were tokens on their own and every occurrence of those letters was
|
|
138
|
-
* substituted wherever it sat — `'mm min ss'` rendered as `'01 1in 01'`, so a pattern
|
|
139
|
-
* could only ever separate its fields with punctuation. That is why the format could not
|
|
140
|
-
* be exposed as a prop: doing so would have published the trap.
|
|
141
|
-
*/
|
|
142
|
-
export function formatTime(ms, format, fps = 25) {
|
|
143
|
-
const totalSeconds = Math.floor(ms / 1000);
|
|
144
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
145
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
146
|
-
const seconds = Math.floor(totalSeconds % 60);
|
|
147
|
-
const frames = Math.floor(((ms % 1000) / 1000) * fps);
|
|
148
|
-
const msRest = Math.floor(ms % 1000);
|
|
149
|
-
// Typed by {@link TimeToken} so the table and the regexp above cannot fall out of step,
|
|
150
|
-
// then read through a widened view: the capture is a `string` as far as the compiler
|
|
151
|
-
// knows, and widening is what lets it be looked up without asserting it back.
|
|
152
|
-
const tokens = {
|
|
153
|
-
hh: String(hours).padStart(2, '0'),
|
|
154
|
-
mm: String(minutes).padStart(2, '0'),
|
|
155
|
-
ss: String(seconds).padStart(2, '0'),
|
|
156
|
-
frame: String(frames).padStart(2, '0'),
|
|
157
|
-
ms: String(msRest).padStart(3, '0'),
|
|
158
|
-
h: String(hours),
|
|
159
|
-
m: String(minutes),
|
|
160
|
-
s: String(seconds),
|
|
161
|
-
f: String(frames)
|
|
162
|
-
};
|
|
163
|
-
const byName = tokens;
|
|
164
|
-
// One pass, so a rendered value can never be re-read as a token by a later pass — the
|
|
165
|
-
// reason the old implementation had to sort its keys by length.
|
|
166
|
-
return format.replace(timeTokenRegexp, (whole, token) => byName[token] ?? whole);
|
|
167
|
-
}
|
|
168
110
|
/**
|
|
169
111
|
* Where along the timeline a click landed.
|
|
170
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,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 remove from './remove/index.js'
|
|
5
4
|
export * as move from './move/index.js'
|
|
5
|
+
export * as remove from './remove/index.js'
|
|
6
6
|
export * as stat from './stat/index.js'
|
|
7
7
|
export * as upload from './upload/index.js'
|
|
@@ -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 remove from './remove/index.js'
|
|
5
4
|
export * as move from './move/index.js'
|
|
5
|
+
export * as remove from './remove/index.js'
|
|
6
6
|
export * as stat from './stat/index.js'
|
|
7
7
|
export * as upload from './upload/index.js'
|
|
@@ -1,12 +1,12 @@
|
|
|
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
7
|
export * as remove from './remove/index.js'
|
|
8
8
|
export * as move from './move/index.js'
|
|
9
|
-
export * as stat from './stat/index.js'
|
|
10
9
|
export * as revokeSignedUrls from './revoke-signed-urls/index.js'
|
|
11
|
-
export * as
|
|
10
|
+
export * as stat from './stat/index.js'
|
|
12
11
|
export * as updateMetadata from './update-metadata/index.js'
|
|
12
|
+
export * as upload from './upload/index.js'
|
|
@@ -1,12 +1,12 @@
|
|
|
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
7
|
export * as remove from './remove/index.js'
|
|
8
8
|
export * as move from './move/index.js'
|
|
9
|
-
export * as stat from './stat/index.js'
|
|
10
9
|
export * as revokeSignedUrls from './revoke-signed-urls/index.js'
|
|
11
|
-
export * as
|
|
10
|
+
export * as stat from './stat/index.js'
|
|
12
11
|
export * as updateMetadata from './update-metadata/index.js'
|
|
12
|
+
export * as upload from './upload/index.js'
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export * as copyFile from './copy-file/index.js'
|
|
2
1
|
export * as copyDir from './copy-dir/index.js'
|
|
2
|
+
export * as copyFile from './copy-file/index.js'
|
|
3
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
|
-
export * as copyFile from './copy-file/index.js'
|
|
2
1
|
export * as copyDir from './copy-dir/index.js'
|
|
2
|
+
export * as copyFile from './copy-file/index.js'
|
|
3
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'
|