@escape-game-over/atlas 0.1.30 → 0.1.31
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/package.json +1 -1
- package/src/astro/carousel.ts +39 -5
package/package.json
CHANGED
package/src/astro/carousel.ts
CHANGED
|
@@ -62,6 +62,17 @@ export interface CarouselOptions {
|
|
|
62
62
|
* renders, and calling would make a project write the first position twice.
|
|
63
63
|
*/
|
|
64
64
|
readonly onChange: (index: number) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Called with `autoplayMs` whenever a countdown to the next automatic
|
|
67
|
+
* advance begins, and with `null` when autoplay stops.
|
|
68
|
+
*
|
|
69
|
+
* For a progress bar. A countdown begins on attach, after every tick and
|
|
70
|
+
* after every manual move, and each one starts from zero — so the bar
|
|
71
|
+
* restarts on every number and stops on `null`, and never has to know why.
|
|
72
|
+
* A hold (hover, focus, a hidden tab, `pause`) and a detach report `null`
|
|
73
|
+
* once, not once per reason.
|
|
74
|
+
*/
|
|
75
|
+
readonly onCountdown?: (ms: number | null) => void;
|
|
65
76
|
}
|
|
66
77
|
|
|
67
78
|
export interface Carousel {
|
|
@@ -107,6 +118,7 @@ export function carousel(options: CarouselOptions): Carousel {
|
|
|
107
118
|
swipeThreshold = 10,
|
|
108
119
|
lockMs = 500,
|
|
109
120
|
onChange,
|
|
121
|
+
onCountdown,
|
|
110
122
|
} = options;
|
|
111
123
|
|
|
112
124
|
/**
|
|
@@ -143,9 +155,19 @@ export function carousel(options: CarouselOptions): Carousel {
|
|
|
143
155
|
*/
|
|
144
156
|
const holds = new Set<string>();
|
|
145
157
|
|
|
158
|
+
/** Whether a countdown is running, so `null` is reported once per stop. */
|
|
159
|
+
let counting = false;
|
|
160
|
+
|
|
161
|
+
const stopAutoplay = (): void => {
|
|
162
|
+
clearInterval(autoplayTimer);
|
|
163
|
+
if (!counting) return;
|
|
164
|
+
counting = false;
|
|
165
|
+
onCountdown?.(null);
|
|
166
|
+
};
|
|
167
|
+
|
|
146
168
|
const hold = (reason: string): void => {
|
|
147
169
|
holds.add(reason);
|
|
148
|
-
|
|
170
|
+
stopAutoplay();
|
|
149
171
|
};
|
|
150
172
|
|
|
151
173
|
const release = (reason: string): void => {
|
|
@@ -171,16 +193,28 @@ export function carousel(options: CarouselOptions): Carousel {
|
|
|
171
193
|
};
|
|
172
194
|
|
|
173
195
|
const restartAutoplay = (): void => {
|
|
174
|
-
clearInterval(autoplayTimer);
|
|
175
196
|
// Nothing to rotate through, nobody watching, or no autoplay asked
|
|
176
197
|
// for — in each case, nothing to schedule.
|
|
177
|
-
if (
|
|
178
|
-
|
|
198
|
+
if (
|
|
199
|
+
autoplayMs === undefined ||
|
|
200
|
+
!canMove ||
|
|
201
|
+
!attached ||
|
|
202
|
+
holds.size > 0
|
|
203
|
+
) {
|
|
204
|
+
stopAutoplay();
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
clearInterval(autoplayTimer);
|
|
179
208
|
autoplayTimer = setInterval(() => {
|
|
180
209
|
// No `restartAutoplay` here: the interval already paces itself, and
|
|
181
210
|
// resetting it from inside its own tick would only churn timers.
|
|
182
211
|
if (claim()) move(index + 1);
|
|
212
|
+
// Reported even when the lock refused the move: the next tick is
|
|
213
|
+
// still `autoplayMs` away either way.
|
|
214
|
+
onCountdown?.(autoplayMs);
|
|
183
215
|
}, autoplayMs);
|
|
216
|
+
counting = true;
|
|
217
|
+
onCountdown?.(autoplayMs);
|
|
184
218
|
};
|
|
185
219
|
|
|
186
220
|
/** The only place `index` changes. `at` may be out of range or negative. */
|
|
@@ -326,7 +360,7 @@ export function carousel(options: CarouselOptions): Carousel {
|
|
|
326
360
|
return () => {
|
|
327
361
|
listeners.abort();
|
|
328
362
|
attached = false;
|
|
329
|
-
|
|
363
|
+
stopAutoplay();
|
|
330
364
|
|
|
331
365
|
// The automatic holds belong to this attachment: an element
|
|
332
366
|
// detached while hovered would otherwise keep "hover" forever,
|