@design-edito/tools 0.5.1 → 0.5.3
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 +1 -1
- package/agnostic/arrays/index.js +1 -1
- package/agnostic/colors/index.d.ts +1 -1
- package/agnostic/colors/index.js +1 -1
- package/agnostic/css/index.d.ts +1 -1
- package/agnostic/css/index.js +1 -1
- package/agnostic/html/deep-select/index.js +5 -3
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.d.ts +9 -9
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.js +9 -9
- package/agnostic/html/hyper-json/smart-tags/isolated/index.d.ts +1 -1
- package/agnostic/html/hyper-json/smart-tags/isolated/index.js +1 -1
- package/agnostic/html/index.d.ts +3 -3
- package/agnostic/html/index.js +3 -3
- package/agnostic/index.d.ts +3 -3
- package/agnostic/index.js +3 -3
- package/agnostic/misc/index.d.ts +1 -1
- package/agnostic/misc/index.js +1 -1
- package/agnostic/misc/logs/index.d.ts +1 -1
- package/agnostic/misc/logs/index.js +1 -1
- 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/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/time/dates/format-date/index.d.ts +4 -2
- package/agnostic/time/dates/format-date/index.js +43 -94
- package/agnostic/time/dates/format-date/index.test.js +154 -0
- package/agnostic/time/dates/format-date/parts.d.ts +28 -0
- package/agnostic/time/dates/format-date/parts.js +136 -0
- package/agnostic/time/dates/format-date/types.d.ts +84 -0
- package/agnostic/time/dates/format-date/types.js +1 -0
- package/agnostic/time/duration/format-duration/index.d.ts +42 -0
- package/agnostic/time/duration/format-duration/index.js +94 -0
- package/agnostic/time/duration/format-duration/index.test.d.ts +1 -0
- package/agnostic/time/duration/format-duration/index.test.js +148 -0
- package/agnostic/time/duration/format-duration/parts.d.ts +32 -0
- package/agnostic/time/duration/format-duration/parts.js +107 -0
- package/agnostic/time/duration/format-duration/types.d.ts +93 -0
- package/agnostic/time/duration/format-duration/types.js +1 -0
- package/agnostic/time/duration/index.d.ts +6 -1
- package/agnostic/time/duration/index.js +2 -2
- package/agnostic/time/duration/index.test.d.ts +1 -0
- package/agnostic/time/duration/index.test.js +168 -0
- package/components/BeforeAfter/index.controlled.d.ts +25 -25
- package/components/BeforeAfter/index.controlled.js +47 -53
- package/components/BeforeAfter/index.d.ts +20 -23
- package/components/BeforeAfter/index.js +48 -40
- package/components/Button/index.js +1 -1
- package/components/Clippable/index.d.ts +17 -26
- package/components/Clippable/index.js +21 -23
- package/components/Disclaimer/index.d.ts +29 -22
- package/components/Disclaimer/index.js +29 -24
- package/components/Drawer/index.d.ts +45 -25
- package/components/Drawer/index.js +61 -52
- package/components/EventListener/index.d.ts +4 -5
- package/components/Gallery/index.d.ts +14 -16
- package/components/Gallery/index.js +25 -30
- package/components/Iframe/index.js +2 -2
- package/components/Image/index.d.ts +5 -12
- package/components/Image/index.js +11 -32
- package/components/Input/index.d.ts +23 -19
- package/components/Input/index.js +30 -20
- package/components/JsonEditor/index.d.ts +177 -9
- package/components/JsonEditor/index.js +133 -75
- package/components/JsonEditor/types.d.ts +11 -0
- package/components/JsonEditor/types.js +1 -0
- package/components/JsonEditor/utils.d.ts +8 -0
- package/components/JsonEditor/utils.js +23 -0
- package/components/ListLoader/index.controlled.d.ts +78 -0
- package/components/ListLoader/index.controlled.js +99 -0
- package/components/ListLoader/index.d.ts +69 -0
- package/components/ListLoader/index.js +146 -0
- package/components/ListLoader/utils.d.ts +8 -0
- package/components/ListLoader/utils.js +10 -0
- package/components/Overlayer/index.js +4 -4
- package/components/Paginator/index.d.ts +7 -12
- package/components/Paginator/index.js +7 -11
- package/components/ResizeObserver/index.d.ts +14 -3
- package/components/ResizeObserver/index.js +49 -24
- package/components/ResizeObserver/styles.module.css +0 -0
- package/components/Scrllgngn/index.d.ts +17 -13
- package/components/Scrllgngn/index.js +25 -84
- package/components/Scrllgngn/utils.d.ts +52 -0
- package/components/Scrllgngn/utils.js +102 -0
- package/components/ScrollListener/index.d.ts +43 -28
- package/components/ScrollListener/index.js +59 -79
- package/components/ScrollListener/utils.d.ts +37 -16
- package/components/ScrollListener/utils.js +141 -28
- package/components/Select/index.d.ts +24 -20
- package/components/Select/index.js +30 -20
- package/components/Sequencer/index.controlled.d.ts +16 -26
- package/components/Sequencer/index.controlled.js +15 -12
- package/components/Sequencer/index.d.ts +25 -30
- package/components/Sequencer/index.js +20 -34
- package/components/Subtitles/index.d.ts +29 -5
- package/components/Subtitles/index.js +90 -12
- package/components/Textarea/index.d.ts +26 -20
- package/components/Textarea/index.js +40 -21
- package/components/Theatre/index.d.ts +35 -39
- package/components/Theatre/index.js +46 -58
- package/components/UIModule/index.d.ts +25 -29
- package/components/UIModule/index.js +81 -110
- package/components/Video/index.controlled.d.ts +51 -51
- package/components/Video/index.controlled.js +75 -72
- package/components/Video/index.d.ts +12 -14
- package/components/Video/index.js +41 -86
- package/components/Video/utils.d.ts +35 -3
- package/components/Video/utils.js +37 -14
- package/components/index.d.ts +5 -4
- package/components/index.js +5 -4
- package/components/public-classnames.d.ts +1 -0
- package/components/public-classnames.js +1 -0
- package/components/utils/index.d.ts +22 -0
- package/components/utils/index.js +31 -0
- package/node/@google-cloud/storage/directory/index.d.ts +2 -2
- package/node/@google-cloud/storage/directory/index.js +2 -2
- package/node/@google-cloud/storage/file/index.d.ts +2 -2
- package/node/@google-cloud/storage/file/index.js +2 -2
- package/node/@google-cloud/storage/index.d.ts +1 -1
- package/node/@google-cloud/storage/index.js +1 -1
- package/node/cloud-storage/operations/index.d.ts +2 -2
- package/node/cloud-storage/operations/index.js +2 -2
- 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/index.d.ts +1 -1
- package/node/images/index.js +1 -1
- package/node/images/transform/operations/index.d.ts +3 -3
- package/node/images/transform/operations/index.js +3 -3
- package/node/index.d.ts +2 -2
- package/node/index.js +2 -2
- 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/node/sftp/file/index.d.ts +1 -1
- package/node/sftp/file/index.js +1 -1
- package/package.json +27 -5
- package/TODO.md +0 -269
- package/components/BeforeAfter/utils.d.ts +0 -4
- package/components/BeforeAfter/utils.js +0 -9
- package/components/Input/index.controlled.d.ts +0 -42
- package/components/Input/index.controlled.js +0 -54
- package/components/Select/index.controlled.d.ts +0 -43
- package/components/Select/index.controlled.js +0 -54
- package/components/Subtitles/types.d.ts +0 -24
- package/components/Subtitles/utils.d.ts +0 -32
- package/components/Subtitles/utils.js +0 -107
- package/components/Textarea/index.controlled.d.ts +0 -50
- package/components/Textarea/index.controlled.js +0 -75
- /package/{components/Subtitles/types.js → agnostic/time/dates/format-date/index.test.d.ts} +0 -0
- /package/components/{ResizeObserver/style.module.css → ListLoader/styles.module.css} +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { days, minutes, seconds } from '../index.js';
|
|
3
|
+
import { formatDuration } from './index.js';
|
|
4
|
+
import { getDurationParts } from './parts.js';
|
|
5
|
+
const DAY = 86400000;
|
|
6
|
+
describe('formatDuration', () => {
|
|
7
|
+
describe('template', () => {
|
|
8
|
+
it('splits the duration across the units the template mentions', () => {
|
|
9
|
+
expect(formatDuration(seconds(3725), '{{h}}:{{mm}}:{{ss}}')).toBe('1:02:05');
|
|
10
|
+
});
|
|
11
|
+
it('puts the whole duration on the only unit a template asks for', () => {
|
|
12
|
+
expect(formatDuration(seconds(3725), '{{s}}s')).toBe('3725s');
|
|
13
|
+
expect(formatDuration(days(400), '{{d}} days')).toBe('400 days');
|
|
14
|
+
});
|
|
15
|
+
it('accepts a plain number of milliseconds in place of a Duration', () => {
|
|
16
|
+
expect(formatDuration(3725000, '{{h}}:{{mm}}:{{ss}}')).toBe('1:02:05');
|
|
17
|
+
});
|
|
18
|
+
it('pads a doubled token to two digits and leaves its bare twin alone', () => {
|
|
19
|
+
expect(formatDuration(minutes(5), '{{mm}}:{{ss}}')).toBe('05:00');
|
|
20
|
+
expect(formatDuration(minutes(5), '{{m}}:{{s}}')).toBe('5:0');
|
|
21
|
+
});
|
|
22
|
+
it('pads milliseconds to three digits', () => {
|
|
23
|
+
expect(formatDuration(1042, '{{s}}.{{ms}}')).toBe('1.042');
|
|
24
|
+
});
|
|
25
|
+
it('substitutes every occurrence of a repeated token', () => {
|
|
26
|
+
expect(formatDuration(seconds(5), '{{s}}/{{s}}')).toBe('5/5');
|
|
27
|
+
});
|
|
28
|
+
it('leaves an unknown token untouched, braces included', () => {
|
|
29
|
+
expect(formatDuration(seconds(5), '{{ZZ}} {{s}}')).toBe('{{ZZ}} 5');
|
|
30
|
+
});
|
|
31
|
+
it('does not substitute a bare letter outside a placeholder', () => {
|
|
32
|
+
expect(formatDuration(seconds(5), 'd h m s {{s}}')).toBe('d h m s 5');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('remainder', () => {
|
|
36
|
+
it('drops the fraction of the smallest unit by default', () => {
|
|
37
|
+
expect(formatDuration(119600, '{{m}}:{{s}}')).toBe('1:59');
|
|
38
|
+
});
|
|
39
|
+
it('keeps the fraction when floorSmallestUnit is off', () => {
|
|
40
|
+
expect(formatDuration(119600, '{{m}}:{{s}}', { floorSmallestUnit: false })).toBe('1:59.6');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('month and year approximation', () => {
|
|
44
|
+
it('counts 365 days as a full year by default', () => {
|
|
45
|
+
expect(formatDuration(days(365), '{{Y}}')).toBe('1');
|
|
46
|
+
});
|
|
47
|
+
it('falls one year short of the Gregorian mean year when the approximation is off', () => {
|
|
48
|
+
expect(formatDuration(days(365), '{{Y}}', { useApproximateMonthAndYear: false })).toBe('0');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('negative durations', () => {
|
|
52
|
+
it('signs every part rather than the string as a whole', () => {
|
|
53
|
+
expect(formatDuration(seconds(-90), '{{m}}:{{ss}}')).toBe('-1:-30');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('getDurationParts', () => {
|
|
58
|
+
describe('breakdown', () => {
|
|
59
|
+
it('cascades the remainder from each unit down to the next', () => {
|
|
60
|
+
expect(getDurationParts(days(400), { units: ['Y', 'd'] })).toMatchObject({
|
|
61
|
+
Y: 1,
|
|
62
|
+
M: 0,
|
|
63
|
+
w: 0,
|
|
64
|
+
d: 35,
|
|
65
|
+
h: 0,
|
|
66
|
+
m: 0,
|
|
67
|
+
s: 0,
|
|
68
|
+
ms: 0
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
it('orders the units itself, whatever order they are given in', () => {
|
|
72
|
+
expect(getDurationParts(3725000, { units: ['s', 'h', 'm'] })).toMatchObject({ h: 1, m: 2, s: 5 });
|
|
73
|
+
});
|
|
74
|
+
it('ignores a unit listed twice', () => {
|
|
75
|
+
expect(getDurationParts(3725000, { units: ['h', 'm', 's', 'h'] })).toMatchObject({ h: 1, m: 2, s: 5 });
|
|
76
|
+
});
|
|
77
|
+
it('reaches every part under its readable name too', () => {
|
|
78
|
+
const parts = getDurationParts(3725000, { units: ['h', 'm', 's'] });
|
|
79
|
+
expect(parts).toMatchObject({
|
|
80
|
+
hours: parts.h,
|
|
81
|
+
minutes: parts.m,
|
|
82
|
+
seconds: parts.s,
|
|
83
|
+
milliseconds: parts.ms,
|
|
84
|
+
days: parts.d,
|
|
85
|
+
weeks: parts.w,
|
|
86
|
+
months: parts.M,
|
|
87
|
+
years: parts.Y
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe('units left out', () => {
|
|
92
|
+
it('puts the whole duration, fraction included, on the largest unit it reaches', () => {
|
|
93
|
+
const parts = getDurationParts(days(400));
|
|
94
|
+
expect(parts.Y).toBeCloseTo(1.0959, 4);
|
|
95
|
+
expect(parts.d).toBe(0);
|
|
96
|
+
});
|
|
97
|
+
it('picks the unit off the duration, not off the largest one that exists', () => {
|
|
98
|
+
expect(getDurationParts(90000).m).toBe(1.5);
|
|
99
|
+
expect(getDurationParts(500).ms).toBe(500);
|
|
100
|
+
});
|
|
101
|
+
it('falls back to milliseconds for a duration shorter than one', () => {
|
|
102
|
+
expect(getDurationParts(0.5)).toMatchObject({ ms: 0.5, s: 0 });
|
|
103
|
+
});
|
|
104
|
+
it('leaves every part at zero for a zero duration', () => {
|
|
105
|
+
expect(getDurationParts(0)).toMatchObject({
|
|
106
|
+
Y: 0, M: 0, w: 0, d: 0, h: 0, m: 0, s: 0, ms: 0
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('floorSmallestUnit', () => {
|
|
111
|
+
it('leaves the remainder on the smallest unit by default', () => {
|
|
112
|
+
expect(getDurationParts(119600, { units: ['m', 's'] })).toMatchObject({ m: 1, s: 59.6 });
|
|
113
|
+
});
|
|
114
|
+
it('truncates the whole duration, so the missing fraction leaves every part', () => {
|
|
115
|
+
expect(getDurationParts(119600, { units: ['m', 's'], floorSmallestUnit: true })).toMatchObject({ m: 1, s: 59 });
|
|
116
|
+
});
|
|
117
|
+
it('rounds off the floating-point dust the cascade leaves behind', () => {
|
|
118
|
+
// 30 days on ['M', 'd'] divides exactly, but only in decimal.
|
|
119
|
+
expect(getDurationParts(30 * DAY, { units: ['M', 'd'], floorSmallestUnit: true })).toMatchObject({ M: 1, d: 0 });
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
describe('month and year approximation', () => {
|
|
123
|
+
it('uses 30-day months and 365-day years by default', () => {
|
|
124
|
+
expect(getDurationParts(365 * DAY, { units: ['Y', 'd'] })).toMatchObject({ Y: 1, d: 0 });
|
|
125
|
+
expect(getDurationParts(30 * DAY, { units: ['M', 'd'] })).toMatchObject({ M: 1, d: 0 });
|
|
126
|
+
});
|
|
127
|
+
it('uses the Gregorian mean year when the approximation is off', () => {
|
|
128
|
+
expect(getDurationParts(365 * DAY, {
|
|
129
|
+
units: ['Y', 'd'],
|
|
130
|
+
useApproximateMonthAndYear: false
|
|
131
|
+
})).toMatchObject({ Y: 0, d: 365 });
|
|
132
|
+
expect(getDurationParts(30 * DAY, {
|
|
133
|
+
units: ['M'],
|
|
134
|
+
useApproximateMonthAndYear: false
|
|
135
|
+
}).M).toBeCloseTo(0.9856, 4);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe('negative durations', () => {
|
|
139
|
+
it('breaks the magnitude down, then negates every part', () => {
|
|
140
|
+
expect(getDurationParts(seconds(-90), { units: ['m', 's'] })).toMatchObject({ m: -1, s: -30 });
|
|
141
|
+
});
|
|
142
|
+
it('leaves an empty part at zero rather than at negative zero', () => {
|
|
143
|
+
const parts = getDurationParts(-30000, { units: ['m', 's'] });
|
|
144
|
+
expect(Object.is(parts.m, 0)).toBe(true);
|
|
145
|
+
expect(parts.s).toBe(-30);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Duration } from '../index.js';
|
|
2
|
+
import type { DurationParts, GetDurationPartsOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Breaks a duration down into its parts, cascading the remainder from each unit
|
|
5
|
+
* to the next.
|
|
6
|
+
*
|
|
7
|
+
* With several units, each one takes its whole part and hands the rest down, so
|
|
8
|
+
* `['M', 'd', 's']` reads as *X months and Y days and Z.mmm seconds*. With a
|
|
9
|
+
* single unit — including the one picked when `units` is omitted — that unit
|
|
10
|
+
* carries the whole duration, fraction included.
|
|
11
|
+
*
|
|
12
|
+
* @param duration - The duration to break down, as a {@link Duration} or a
|
|
13
|
+
* number of milliseconds.
|
|
14
|
+
* @param options - Which units to use, and how to handle the remainder.
|
|
15
|
+
* @returns The parts, each one reachable under its unit token and under its
|
|
16
|
+
* readable name. Units left out of the breakdown are `0`.
|
|
17
|
+
* @see {@link DurationParts}
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* A negative duration is broken down by magnitude, then every part is negated.
|
|
21
|
+
* `floorSmallestUnit` truncates the duration *before* the cascade, so the whole
|
|
22
|
+
* breakdown describes the truncated duration rather than the original one —
|
|
23
|
+
* `1m 59.6s` gives `1m 59s`, and the missing `.6s` is gone from every part.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* getDurationParts(days(400), { units: ['Y', 'd'] })
|
|
27
|
+
* // => { Y: 1, years: 1, d: 35, days: 35, … every other unit at 0 }
|
|
28
|
+
*
|
|
29
|
+
* getDurationParts(days(400))
|
|
30
|
+
* // => { Y: 1.0958…, years: 1.0958…, … } — the largest unit it reaches
|
|
31
|
+
*/
|
|
32
|
+
export declare function getDurationParts(duration: Duration | number, options?: GetDurationPartsOptions): DurationParts;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Duration } from '../index.js';
|
|
2
|
+
const SECOND = 1000;
|
|
3
|
+
const MINUTE = 60 * SECOND;
|
|
4
|
+
const HOUR = 60 * MINUTE;
|
|
5
|
+
const DAY = 24 * HOUR;
|
|
6
|
+
const WEEK = 7 * DAY;
|
|
7
|
+
const APPROXIMATE_YEAR = 365 * DAY;
|
|
8
|
+
const APPROXIMATE_MONTH = 30 * DAY;
|
|
9
|
+
/** The Gregorian mean year — 365.2425 days, the calendar's actual average. */
|
|
10
|
+
const EXACT_YEAR = 365.2425 * DAY;
|
|
11
|
+
const EXACT_MONTH = EXACT_YEAR / 12;
|
|
12
|
+
/** Units from the longest to the shortest, in both approximation modes. */
|
|
13
|
+
const unitsLongestFirst = ['Y', 'M', 'w', 'd', 'h', 'm', 's', 'ms'];
|
|
14
|
+
/** How many milliseconds each unit is worth, under the chosen approximation. */
|
|
15
|
+
function unitLengths(useApproximateMonthAndYear) {
|
|
16
|
+
return {
|
|
17
|
+
ms: 1,
|
|
18
|
+
s: SECOND,
|
|
19
|
+
m: MINUTE,
|
|
20
|
+
h: HOUR,
|
|
21
|
+
d: DAY,
|
|
22
|
+
w: WEEK,
|
|
23
|
+
M: useApproximateMonthAndYear ? APPROXIMATE_MONTH : EXACT_MONTH,
|
|
24
|
+
Y: useApproximateMonthAndYear ? APPROXIMATE_YEAR : EXACT_YEAR
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The requested units, deduplicated and ordered longest first. Falls back to the
|
|
29
|
+
* single largest unit the duration reaches, and to `'ms'` for a duration shorter
|
|
30
|
+
* than a millisecond.
|
|
31
|
+
*/
|
|
32
|
+
function resolveUnits(units, absoluteMs, lengths) {
|
|
33
|
+
if (units !== undefined && units.length > 0) {
|
|
34
|
+
return unitsLongestFirst.filter(unit => units.includes(unit));
|
|
35
|
+
}
|
|
36
|
+
return [unitsLongestFirst.find(unit => absoluteMs >= lengths[unit]) ?? 'ms'];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Breaks a duration down into its parts, cascading the remainder from each unit
|
|
40
|
+
* to the next.
|
|
41
|
+
*
|
|
42
|
+
* With several units, each one takes its whole part and hands the rest down, so
|
|
43
|
+
* `['M', 'd', 's']` reads as *X months and Y days and Z.mmm seconds*. With a
|
|
44
|
+
* single unit — including the one picked when `units` is omitted — that unit
|
|
45
|
+
* carries the whole duration, fraction included.
|
|
46
|
+
*
|
|
47
|
+
* @param duration - The duration to break down, as a {@link Duration} or a
|
|
48
|
+
* number of milliseconds.
|
|
49
|
+
* @param options - Which units to use, and how to handle the remainder.
|
|
50
|
+
* @returns The parts, each one reachable under its unit token and under its
|
|
51
|
+
* readable name. Units left out of the breakdown are `0`.
|
|
52
|
+
* @see {@link DurationParts}
|
|
53
|
+
*
|
|
54
|
+
* @remarks
|
|
55
|
+
* A negative duration is broken down by magnitude, then every part is negated.
|
|
56
|
+
* `floorSmallestUnit` truncates the duration *before* the cascade, so the whole
|
|
57
|
+
* breakdown describes the truncated duration rather than the original one —
|
|
58
|
+
* `1m 59.6s` gives `1m 59s`, and the missing `.6s` is gone from every part.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* getDurationParts(days(400), { units: ['Y', 'd'] })
|
|
62
|
+
* // => { Y: 1, years: 1, d: 35, days: 35, … every other unit at 0 }
|
|
63
|
+
*
|
|
64
|
+
* getDurationParts(days(400))
|
|
65
|
+
* // => { Y: 1.0958…, years: 1.0958…, … } — the largest unit it reaches
|
|
66
|
+
*/
|
|
67
|
+
export function getDurationParts(duration, options = {}) {
|
|
68
|
+
const { units, floorSmallestUnit = false, useApproximateMonthAndYear = true } = options;
|
|
69
|
+
const totalMs = duration instanceof Duration ? duration.toMs() : duration;
|
|
70
|
+
const sign = totalMs < 0 ? -1 : 1;
|
|
71
|
+
const lengths = unitLengths(useApproximateMonthAndYear);
|
|
72
|
+
const usedUnits = resolveUnits(units, Math.abs(totalMs), lengths);
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
74
|
+
const smallestUnit = usedUnits[usedUnits.length - 1];
|
|
75
|
+
const smallestLength = lengths[smallestUnit];
|
|
76
|
+
let remaining = Math.abs(totalMs);
|
|
77
|
+
if (floorSmallestUnit) {
|
|
78
|
+
remaining = Math.floor(remaining / smallestLength) * smallestLength;
|
|
79
|
+
}
|
|
80
|
+
const values = {
|
|
81
|
+
ms: 0, s: 0, m: 0, h: 0, d: 0, w: 0, M: 0, Y: 0
|
|
82
|
+
};
|
|
83
|
+
usedUnits.forEach((unit, pos) => {
|
|
84
|
+
const isSmallest = pos === usedUnits.length - 1;
|
|
85
|
+
const exact = remaining / lengths[unit];
|
|
86
|
+
// Math.round, not Math.floor, and deliberately so: the truncation already
|
|
87
|
+
// happened above, on the whole duration, so this value is a whole one by
|
|
88
|
+
// now. Rounding only clears the floating-point dust the divisions leave —
|
|
89
|
+
// flooring here would turn a 29.999999999 that means 30 into a 29.
|
|
90
|
+
const value = isSmallest
|
|
91
|
+
? (floorSmallestUnit ? Math.round(exact) : exact)
|
|
92
|
+
: Math.floor(exact);
|
|
93
|
+
values[unit] = value === 0 ? 0 : value * sign;
|
|
94
|
+
remaining -= value * lengths[unit];
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
...values,
|
|
98
|
+
milliseconds: values.ms,
|
|
99
|
+
seconds: values.s,
|
|
100
|
+
minutes: values.m,
|
|
101
|
+
hours: values.h,
|
|
102
|
+
days: values.d,
|
|
103
|
+
weeks: values.w,
|
|
104
|
+
months: values.M,
|
|
105
|
+
years: values.Y
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The units a duration can be broken down into, keyed the way `format-date`
|
|
3
|
+
* tokens are — `'m'` is minutes, `'M'` is months.
|
|
4
|
+
*/
|
|
5
|
+
export type DurationUnit = 'ms' | 's' | 'm' | 'h' | 'd' | 'w' | 'M' | 'Y';
|
|
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';
|
|
8
|
+
/** Options for `getDurationParts`. */
|
|
9
|
+
export type GetDurationPartsOptions = {
|
|
10
|
+
/**
|
|
11
|
+
* The units to break the duration down into, in any order. Omitted or empty,
|
|
12
|
+
* a single unit is picked: the largest one the duration reaches.
|
|
13
|
+
*/
|
|
14
|
+
units?: DurationUnit[];
|
|
15
|
+
/**
|
|
16
|
+
* Truncates the duration to a whole number of the smallest requested unit, so
|
|
17
|
+
* no part comes out fractional. Defaults to `false`, which leaves the
|
|
18
|
+
* remainder on the smallest unit.
|
|
19
|
+
*/
|
|
20
|
+
floorSmallestUnit?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Months and years have no fixed length, so they are approximated. `true`
|
|
23
|
+
* (the default) uses 30-day months and 365-day years, matching what
|
|
24
|
+
* `Duration` itself computes. `false` uses the Gregorian mean year of
|
|
25
|
+
* 365.2425 days and a month of exactly a twelfth of it.
|
|
26
|
+
*/
|
|
27
|
+
useApproximateMonthAndYear?: boolean;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* A duration's parts, keyed by unit token.
|
|
31
|
+
*
|
|
32
|
+
* Every unit is present: those left out of the breakdown are `0`. All parts
|
|
33
|
+
* carry the sign of the input duration.
|
|
34
|
+
*/
|
|
35
|
+
export type DurationTokenParts = {
|
|
36
|
+
/** Milliseconds. */
|
|
37
|
+
ms: number;
|
|
38
|
+
/** Seconds. */
|
|
39
|
+
s: number;
|
|
40
|
+
/** Minutes. */
|
|
41
|
+
m: number;
|
|
42
|
+
/** Hours. */
|
|
43
|
+
h: number;
|
|
44
|
+
/** Days. */
|
|
45
|
+
d: number;
|
|
46
|
+
/** Weeks. */
|
|
47
|
+
w: number;
|
|
48
|
+
/** Months. */
|
|
49
|
+
M: number;
|
|
50
|
+
/** Years. */
|
|
51
|
+
Y: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* The same parts as {@link DurationTokenParts}, under names that read on their
|
|
55
|
+
* own — one per token, same value.
|
|
56
|
+
*/
|
|
57
|
+
export type NamedDurationParts = {
|
|
58
|
+
/** {@link DurationTokenParts.ms} */
|
|
59
|
+
milliseconds: number;
|
|
60
|
+
/** {@link DurationTokenParts.s} */
|
|
61
|
+
seconds: number;
|
|
62
|
+
/** {@link DurationTokenParts.m} */
|
|
63
|
+
minutes: number;
|
|
64
|
+
/** {@link DurationTokenParts.h} */
|
|
65
|
+
hours: number;
|
|
66
|
+
/** {@link DurationTokenParts.d} */
|
|
67
|
+
days: number;
|
|
68
|
+
/** {@link DurationTokenParts.w} */
|
|
69
|
+
weeks: number;
|
|
70
|
+
/** {@link DurationTokenParts.M} */
|
|
71
|
+
months: number;
|
|
72
|
+
/** {@link DurationTokenParts.Y} */
|
|
73
|
+
years: number;
|
|
74
|
+
};
|
|
75
|
+
/** Every part of a duration, reachable both by unit token and by name. */
|
|
76
|
+
export type DurationParts = DurationTokenParts & NamedDurationParts;
|
|
77
|
+
/** Options for `formatDuration`. */
|
|
78
|
+
export type FormatDurationOptions = {
|
|
79
|
+
/**
|
|
80
|
+
* Truncates the duration to a whole number of the smallest unit the template
|
|
81
|
+
* uses. Defaults to `true` here, unlike {@link GetDurationPartsOptions} — a
|
|
82
|
+
* template asks to be displayed, and `0:01:59.60000000001` is not a display.
|
|
83
|
+
* Set it to `false` to keep the fraction.
|
|
84
|
+
*/
|
|
85
|
+
floorSmallestUnit?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Months and years have no fixed length, so they are approximated. `true`
|
|
88
|
+
* (the default) uses 30-day months and 365-day years, matching what
|
|
89
|
+
* `Duration` itself computes. `false` uses the Gregorian mean year of
|
|
90
|
+
* 365.2425 days and a month of exactly a twelfth of it.
|
|
91
|
+
*/
|
|
92
|
+
useApproximateMonthAndYear?: boolean;
|
|
93
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -4,8 +4,13 @@
|
|
|
4
4
|
export type DurationType = 'milliseconds' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months' | 'years';
|
|
5
5
|
/**
|
|
6
6
|
* Supported duration types (short form aliases).
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* `'M'` and `'Y'` are the `format-date` style tokens, and the ones
|
|
10
|
+
* {@link DurationUnit} is keyed on; `'mo'`, `'mth'` and `'y'` predate them and
|
|
11
|
+
* stay accepted. Mind the casing: `'m'` is minutes, `'M'` is months.
|
|
7
12
|
*/
|
|
8
|
-
export type DurationTypeShort = 'ms' | 's' | 'sec' | 'min' | 'm' | 'h' | 'd' | 'w' | 'mo' | 'mth' | 'y';
|
|
13
|
+
export type DurationTypeShort = 'ms' | 's' | 'sec' | 'min' | 'm' | 'h' | 'd' | 'w' | 'mo' | 'mth' | 'M' | 'y' | 'Y';
|
|
9
14
|
/**
|
|
10
15
|
* Represents a duration in a specific unit and allows conversion to other units.
|
|
11
16
|
*/
|
|
@@ -38,11 +38,11 @@ export class Duration {
|
|
|
38
38
|
else if (type === 'w' || type === 'weeks') {
|
|
39
39
|
this.type = 'weeks';
|
|
40
40
|
}
|
|
41
|
-
else if (type === 'mo' || type === 'mth' || type === 'months') {
|
|
41
|
+
else if (type === 'mo' || type === 'mth' || type === 'M' || type === 'months') {
|
|
42
42
|
this.type = 'months';
|
|
43
43
|
}
|
|
44
44
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
45
|
-
else if (type === 'y' || type === 'years') {
|
|
45
|
+
else if (type === 'y' || type === 'Y' || type === 'years') {
|
|
46
46
|
this.type = 'years';
|
|
47
47
|
}
|
|
48
48
|
else {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { Duration, d, days, h, hours, m, milliseconds, min, minutes, months, ms, mth, s, sec, seconds, w, weeks, y, years, yr } from './index.js';
|
|
3
|
+
describe('Duration', () => {
|
|
4
|
+
describe('unit normalisation', () => {
|
|
5
|
+
it('keeps a long form as it is given', () => {
|
|
6
|
+
expect(new Duration(1, 'milliseconds').type).toBe('milliseconds');
|
|
7
|
+
expect(new Duration(1, 'seconds').type).toBe('seconds');
|
|
8
|
+
expect(new Duration(1, 'minutes').type).toBe('minutes');
|
|
9
|
+
expect(new Duration(1, 'hours').type).toBe('hours');
|
|
10
|
+
expect(new Duration(1, 'days').type).toBe('days');
|
|
11
|
+
expect(new Duration(1, 'weeks').type).toBe('weeks');
|
|
12
|
+
expect(new Duration(1, 'months').type).toBe('months');
|
|
13
|
+
expect(new Duration(1, 'years').type).toBe('years');
|
|
14
|
+
});
|
|
15
|
+
it('expands a short form to its long form', () => {
|
|
16
|
+
expect(new Duration(1, 'ms').type).toBe('milliseconds');
|
|
17
|
+
expect(new Duration(1, 's').type).toBe('seconds');
|
|
18
|
+
expect(new Duration(1, 'sec').type).toBe('seconds');
|
|
19
|
+
expect(new Duration(1, 'min').type).toBe('minutes');
|
|
20
|
+
expect(new Duration(1, 'h').type).toBe('hours');
|
|
21
|
+
expect(new Duration(1, 'd').type).toBe('days');
|
|
22
|
+
expect(new Duration(1, 'w').type).toBe('weeks');
|
|
23
|
+
});
|
|
24
|
+
it('tells minutes from months by the case of the token', () => {
|
|
25
|
+
expect(new Duration(1, 'm').type).toBe('minutes');
|
|
26
|
+
expect(new Duration(1, 'M').type).toBe('months');
|
|
27
|
+
});
|
|
28
|
+
it('still accepts the month and year aliases that predate the format-date tokens', () => {
|
|
29
|
+
expect(new Duration(1, 'mo').type).toBe('months');
|
|
30
|
+
expect(new Duration(1, 'mth').type).toBe('months');
|
|
31
|
+
expect(new Duration(1, 'y').type).toBe('years');
|
|
32
|
+
expect(new Duration(1, 'Y').type).toBe('years');
|
|
33
|
+
});
|
|
34
|
+
it('falls back to milliseconds on a unit it does not know', () => {
|
|
35
|
+
// The fallback is unreachable through the types — only a caller in plain JS
|
|
36
|
+
// gets there, and it is that caller the test stands in for.
|
|
37
|
+
const duration = new Duration(5, 'fortnights');
|
|
38
|
+
expect(duration.type).toBe('milliseconds');
|
|
39
|
+
expect(duration.toMs()).toBe(5);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('toMilliseconds', () => {
|
|
43
|
+
it('converts each unit by its fixed length', () => {
|
|
44
|
+
expect(milliseconds(1).toMilliseconds()).toBe(1);
|
|
45
|
+
expect(seconds(1).toMilliseconds()).toBe(1000);
|
|
46
|
+
expect(minutes(1).toMilliseconds()).toBe(60000);
|
|
47
|
+
expect(hours(1).toMilliseconds()).toBe(3600000);
|
|
48
|
+
expect(days(1).toMilliseconds()).toBe(86400000);
|
|
49
|
+
expect(weeks(1).toMilliseconds()).toBe(604800000);
|
|
50
|
+
});
|
|
51
|
+
it('approximates a month as 30 days and a year as 365', () => {
|
|
52
|
+
expect(months(1).toMilliseconds()).toBe(30 * 86400000);
|
|
53
|
+
expect(years(1).toMilliseconds()).toBe(365 * 86400000);
|
|
54
|
+
});
|
|
55
|
+
it('carries the sign and the fraction of the value it was given', () => {
|
|
56
|
+
expect(seconds(-90).toMilliseconds()).toBe(-90000);
|
|
57
|
+
expect(hours(1.5).toMilliseconds()).toBe(5400000);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe('conversions to other units', () => {
|
|
61
|
+
it('reads a duration back in a larger unit', () => {
|
|
62
|
+
expect(seconds(90).toMinutes()).toBe(1.5);
|
|
63
|
+
expect(minutes(90).toHours()).toBe(1.5);
|
|
64
|
+
expect(hours(36).toDays()).toBe(1.5);
|
|
65
|
+
expect(days(14).toWeeks()).toBe(2);
|
|
66
|
+
});
|
|
67
|
+
it('reads a duration back in a smaller unit', () => {
|
|
68
|
+
expect(hours(2).toSeconds()).toBe(7200);
|
|
69
|
+
expect(days(1).toMinutes()).toBe(1440);
|
|
70
|
+
});
|
|
71
|
+
it('divides by the same month and year approximations it multiplies by', () => {
|
|
72
|
+
expect(days(30).toMonths()).toBe(1);
|
|
73
|
+
expect(days(365).toYear()).toBe(1);
|
|
74
|
+
});
|
|
75
|
+
it('yields a fractional value rather than a truncated one', () => {
|
|
76
|
+
expect(seconds(30).toMinutes()).toBe(0.5);
|
|
77
|
+
expect(days(400).toYear()).toBeCloseTo(1.0959, 4);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('shorthand aliases', () => {
|
|
81
|
+
it('exposes a shorthand for every conversion', () => {
|
|
82
|
+
const duration = minutes(3);
|
|
83
|
+
expect(duration.toMs()).toBe(duration.toMilliseconds());
|
|
84
|
+
expect(duration.toS()).toBe(duration.toSeconds());
|
|
85
|
+
expect(duration.toSec()).toBe(duration.toSeconds());
|
|
86
|
+
expect(duration.toM()).toBe(duration.toMinutes());
|
|
87
|
+
expect(duration.toMin()).toBe(duration.toMinutes());
|
|
88
|
+
expect(duration.toH()).toBe(duration.toHours());
|
|
89
|
+
expect(duration.toD()).toBe(duration.toDays());
|
|
90
|
+
expect(duration.toW()).toBe(duration.toWeeks());
|
|
91
|
+
expect(duration.toMth()).toBe(duration.toMonths());
|
|
92
|
+
expect(duration.toY()).toBe(duration.toYear());
|
|
93
|
+
expect(duration.toYr()).toBe(duration.toYear());
|
|
94
|
+
});
|
|
95
|
+
it('keeps its conversions bound once they are detached from the instance', () => {
|
|
96
|
+
const { toMs, toMinutes } = hours(2);
|
|
97
|
+
expect(toMs()).toBe(7200000);
|
|
98
|
+
expect(toMinutes()).toBe(120);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe('milliseconds', () => {
|
|
103
|
+
it('builds a duration counted in milliseconds', () => {
|
|
104
|
+
expect(milliseconds(250)).toMatchObject({ value: 250, type: 'milliseconds' });
|
|
105
|
+
});
|
|
106
|
+
it('is also exported as ms', () => {
|
|
107
|
+
expect(ms).toBe(milliseconds);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('seconds', () => {
|
|
111
|
+
it('builds a duration counted in seconds', () => {
|
|
112
|
+
expect(seconds(30)).toMatchObject({ value: 30, type: 'seconds' });
|
|
113
|
+
});
|
|
114
|
+
it('is also exported as s and sec', () => {
|
|
115
|
+
expect(s).toBe(seconds);
|
|
116
|
+
expect(sec).toBe(seconds);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('minutes', () => {
|
|
120
|
+
it('builds a duration counted in minutes', () => {
|
|
121
|
+
expect(minutes(45)).toMatchObject({ value: 45, type: 'minutes' });
|
|
122
|
+
});
|
|
123
|
+
it('is also exported as m and min', () => {
|
|
124
|
+
expect(m).toBe(minutes);
|
|
125
|
+
expect(min).toBe(minutes);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe('hours', () => {
|
|
129
|
+
it('builds a duration counted in hours', () => {
|
|
130
|
+
expect(hours(12)).toMatchObject({ value: 12, type: 'hours' });
|
|
131
|
+
});
|
|
132
|
+
it('is also exported as h', () => {
|
|
133
|
+
expect(h).toBe(hours);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe('days', () => {
|
|
137
|
+
it('builds a duration counted in days', () => {
|
|
138
|
+
expect(days(7)).toMatchObject({ value: 7, type: 'days' });
|
|
139
|
+
});
|
|
140
|
+
it('is also exported as d', () => {
|
|
141
|
+
expect(d).toBe(days);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
describe('weeks', () => {
|
|
145
|
+
it('builds a duration counted in weeks', () => {
|
|
146
|
+
expect(weeks(3)).toMatchObject({ value: 3, type: 'weeks' });
|
|
147
|
+
});
|
|
148
|
+
it('is also exported as w', () => {
|
|
149
|
+
expect(w).toBe(weeks);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('months', () => {
|
|
153
|
+
it('builds a duration counted in months', () => {
|
|
154
|
+
expect(months(2)).toMatchObject({ value: 2, type: 'months' });
|
|
155
|
+
});
|
|
156
|
+
it('is also exported as mth', () => {
|
|
157
|
+
expect(mth).toBe(months);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('years', () => {
|
|
161
|
+
it('builds a duration counted in years', () => {
|
|
162
|
+
expect(years(1)).toMatchObject({ value: 1, type: 'years' });
|
|
163
|
+
});
|
|
164
|
+
it('is also exported as y and yr', () => {
|
|
165
|
+
expect(y).toBe(years);
|
|
166
|
+
expect(yr).toBe(years);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
@@ -1,45 +1,39 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type FunctionComponent, type PropsWithChildren, type ReactNode } from 'react';
|
|
2
2
|
import type { WithClassName } from '../utils/types.js';
|
|
3
3
|
/**
|
|
4
|
-
* Props for the {@link
|
|
5
|
-
*
|
|
6
|
-
* Extends {@link WithClassName} with layout, content, and interaction configuration.
|
|
4
|
+
* Props for the {@link ControlledBeforeAfter} component.
|
|
7
5
|
*
|
|
8
6
|
* @property mode - Layout orientation of the split. Defaults to `'horizontal'`.
|
|
9
|
-
* @property ratio - Position of the divider
|
|
10
|
-
*
|
|
7
|
+
* @property ratio - Position of the divider, between `0` and `1`. Values outside
|
|
8
|
+
* that range are clamped. Defaults to `0`.
|
|
11
9
|
* @property before - Content rendered in the first (before) panel.
|
|
12
10
|
* @property after - Content rendered in the second (after) panel.
|
|
13
|
-
* @property
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* x and y ratios of the release position.
|
|
11
|
+
* @property onDragged - Called on each pointer move while dragging, with the
|
|
12
|
+
* pointer's x and y ratios relative to the component's bounds.
|
|
13
|
+
* @property onClicked - Called on pointer release when no drag occurred, with
|
|
14
|
+
* the release position's x and y ratios.
|
|
18
15
|
* @property className - Additional class name(s) applied to the root element.
|
|
19
|
-
* @property children - Arbitrary content to inject inside the component
|
|
16
|
+
* @property children - Arbitrary content to inject inside the component.
|
|
20
17
|
*/
|
|
21
18
|
export type Props = PropsWithChildren<WithClassName<{
|
|
22
19
|
mode?: 'vertical' | 'horizontal';
|
|
23
20
|
ratio?: number;
|
|
24
21
|
before?: ReactNode;
|
|
25
22
|
after?: ReactNode;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
clicked?: (xRatio: number, yRatio: number) => void;
|
|
29
|
-
};
|
|
23
|
+
onDragged?: (xRatio: number, yRatio: number) => void;
|
|
24
|
+
onClicked?: (xRatio: number, yRatio: number) => void;
|
|
30
25
|
}>>;
|
|
31
26
|
/**
|
|
32
27
|
* Controlled before/after comparison component.
|
|
33
28
|
*
|
|
34
|
-
* Renders two content panels separated by a
|
|
35
|
-
*
|
|
36
|
-
*
|
|
29
|
+
* Renders two content panels separated by a divider whose position is expressed
|
|
30
|
+
* as a ratio between `0` and `1`. Handles both mouse and touch input, telling a
|
|
31
|
+
* click apart from a drag.
|
|
37
32
|
*
|
|
38
33
|
* The active ratio is exposed as:
|
|
39
|
-
* - CSS custom properties
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* - A `data-ratio` attribute on the root element.
|
|
34
|
+
* - CSS custom properties `--lm-before-after-ratio` and
|
|
35
|
+
* `--lm-before-after-ratio-percent`,
|
|
36
|
+
* - a `data-ratio` attribute on the root element.
|
|
43
37
|
*
|
|
44
38
|
* ### CSS modifiers
|
|
45
39
|
* - `horizontal` — applied when `mode` is `'horizontal'`.
|
|
@@ -48,9 +42,15 @@ export type Props = PropsWithChildren<WithClassName<{
|
|
|
48
42
|
* ### CSS elements
|
|
49
43
|
* - `before`
|
|
50
44
|
* - `after`
|
|
45
|
+
* - `separator`
|
|
51
46
|
*
|
|
52
47
|
* @param props - Component properties.
|
|
53
48
|
* @see {@link Props}
|
|
54
|
-
* @returns A split-panel container
|
|
49
|
+
* @returns A split-panel container reporting pointer interactions as ratios.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* The component holds no ratio state: it only reports where the pointer is, and
|
|
53
|
+
* renders whatever `ratio` it is given. Turning one into the other is the
|
|
54
|
+
* uncontrolled wrapper's job.
|
|
55
55
|
*/
|
|
56
|
-
export declare const
|
|
56
|
+
export declare const ControlledBeforeAfter: FunctionComponent<Props>;
|