@escape-game-over/atlas 0.1.111 → 0.1.112
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/docs/checks.md +1 -1
- package/docs/client-scripts.md +6 -0
- package/package.json +1 -1
- package/src/astro/filters.ts +27 -4
package/docs/checks.md
CHANGED
|
@@ -132,7 +132,7 @@ dependencies at all. Vitest type-checks them itself when it runs them.
|
|
|
132
132
|
| `money.test.ts` | a bare count widened to a band, the span of a table, the gaps and overlaps that throw, and an audience priced twice |
|
|
133
133
|
| `url.test.ts` | joining an origin to a path exactly once, and normalising the origin an `@id` is built from |
|
|
134
134
|
| `warn.test.ts` | the shared prefix, and reducing a URL to its path |
|
|
135
|
-
| `filters.test.ts` | folding both sides of a query, how each kind narrows, the four URL decisions, and attach/detach
|
|
135
|
+
| `filters.test.ts` | folding both sides of a query, how each kind narrows, the four URL decisions, values no item holds, and attach/detach |
|
|
136
136
|
| `filters-view.test.ts` | the write-back into the input and that it is skipped when unchanged, clear taking focus, and the nesting order |
|
|
137
137
|
| `build-cache.test.ts` | that an unset `CI_ASTRO_CACHE` yields nothing, so Astro's own `cacheDir` default survives |
|
|
138
138
|
|
package/docs/client-scripts.md
CHANGED
|
@@ -241,6 +241,12 @@ instead of flashing the whole list back. Nothing writes to the URL before
|
|
|
241
241
|
`attach`, because `attach` is what reads it — a `set` on an unattached instance
|
|
242
242
|
would overwrite state nobody had loaded.
|
|
243
243
|
|
|
244
|
+
A choice no item holds, or a flag no item carries, is a stale or mistyped link:
|
|
245
|
+
reading it — on `attach` and on the back button — takes it as no choice, and
|
|
246
|
+
replaces the URL without it. Otherwise `?category=castle` showed an empty list
|
|
247
|
+
with nothing pressed, not even "All". A `text` query is left alone: it matches
|
|
248
|
+
words, not values, and finding nothing is a fair answer to it.
|
|
249
|
+
|
|
244
250
|
A flag is on by being there, as an HTML boolean attribute is: written as the bare
|
|
245
251
|
`?featured`, and **absent** when off. Reading asks only whether the name is
|
|
246
252
|
present, so `?featured=1` from an older link still reads as on — and so does a
|
package/package.json
CHANGED
package/src/astro/filters.ts
CHANGED
|
@@ -199,6 +199,18 @@ export function filters<const F extends FieldMap, T>(
|
|
|
199
199
|
return { item, values, haystacks };
|
|
200
200
|
});
|
|
201
201
|
|
|
202
|
+
// What the items hold, per choice and flag: a link asking for anything
|
|
203
|
+
// else is stale or mistyped, and is read as no choice rather than an empty
|
|
204
|
+
// list with nothing pressed.
|
|
205
|
+
const held = new Map<string, ReadonlySet<unknown>>();
|
|
206
|
+
for (const name of names) {
|
|
207
|
+
if (kindOf(name) === "text") continue;
|
|
208
|
+
held.set(
|
|
209
|
+
name,
|
|
210
|
+
new Set(entries.flatMap((entry) => entry.values[name] as unknown))
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
202
214
|
const empty = (name: keyof F & string): StateValue<F[typeof name]> =>
|
|
203
215
|
(kindOf(name) === "flag" ? false : "") as StateValue<F[typeof name]>;
|
|
204
216
|
|
|
@@ -287,9 +299,11 @@ export function filters<const F extends FieldMap, T>(
|
|
|
287
299
|
matched = next;
|
|
288
300
|
}
|
|
289
301
|
|
|
290
|
-
|
|
302
|
+
/** Applies the URL; says whether it asked for anything no item holds. */
|
|
303
|
+
function readUrl(): boolean {
|
|
291
304
|
const search = new URLSearchParams(window.location.search);
|
|
292
305
|
const next: Record<string, string | boolean> = {};
|
|
306
|
+
let dropped = false;
|
|
293
307
|
for (const name of names) {
|
|
294
308
|
if (!inUrl.includes(name)) {
|
|
295
309
|
// A state-only field is not in the URL, so the URL has nothing
|
|
@@ -300,12 +314,17 @@ export function filters<const F extends FieldMap, T>(
|
|
|
300
314
|
}
|
|
301
315
|
// A flag is on by being there, as an HTML boolean attribute is:
|
|
302
316
|
// `?featured`, and `?featured=1` from an older link, alike.
|
|
303
|
-
|
|
317
|
+
const value =
|
|
304
318
|
kindOf(name) === "flag"
|
|
305
319
|
? search.has(name)
|
|
306
320
|
: (search.get(name) ?? "");
|
|
321
|
+
const unheld =
|
|
322
|
+
value !== empty(name) && held.get(name)?.has(value) === false;
|
|
323
|
+
next[name] = unheld ? empty(name) : value;
|
|
324
|
+
if (unheld) dropped = true;
|
|
307
325
|
}
|
|
308
326
|
state = next as FilterState<F>;
|
|
327
|
+
return dropped;
|
|
309
328
|
}
|
|
310
329
|
|
|
311
330
|
function writeUrl(history: "push" | "replace"): void {
|
|
@@ -424,8 +443,9 @@ export function filters<const F extends FieldMap, T>(
|
|
|
424
443
|
window.addEventListener(
|
|
425
444
|
"popstate",
|
|
426
445
|
() => {
|
|
427
|
-
readUrl();
|
|
446
|
+
const dropped = readUrl();
|
|
428
447
|
recompute();
|
|
448
|
+
if (dropped) writeUrl("replace");
|
|
429
449
|
announce();
|
|
430
450
|
},
|
|
431
451
|
{ signal: events.signal }
|
|
@@ -435,8 +455,11 @@ export function filters<const F extends FieldMap, T>(
|
|
|
435
455
|
// Read before the first announcement: the URL may already carry a
|
|
436
456
|
// state, and announcing the empty one first flashes the unfiltered
|
|
437
457
|
// list over it.
|
|
438
|
-
|
|
458
|
+
// A value no item holds leaves the address bar as well, replaced
|
|
459
|
+
// rather than pushed: it is a correction, not a step to go back to.
|
|
460
|
+
const dropped = readUrl();
|
|
439
461
|
recompute();
|
|
462
|
+
if (dropped) writeUrl("replace");
|
|
440
463
|
announce();
|
|
441
464
|
|
|
442
465
|
return () => {
|