also looking at this
Promote main to production: signed-out chrome and the subscriber tables
#17
54 files
+4252
-1353
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -244,7 +244,7 @@ | ||
| 244 | 244 | |
| 245 | 245 | "@stacksjs/ts-cloud": ["@stacksjs/ts-cloud@0.16.40", "", { "dependencies": { "@stacksjs/ts-xml": "^0.1.2", "@ts-cloud/aws-types": "0.16.40", "@ts-cloud/core": "0.16.40", "hash-wasm": "^4.12.0" }, "bin": { "cloud": "./dist/bin/cli.js" } }, "sha512-q2km71gzbBUO6aSvJci2BMkNVXjzv0uiUl1K65QautSov9cULz+nV0Mpy4meHYkRqSpq9SUTjU28t9zJiqDesA=="], |
| 246 | 246 | |
| 247 | "@stacksjs/ts-css": ["@stacksjs/ts-css@0.3.15", "", { "dependencies": { "@stacksjs/clapp": "^0.2.0", "bunfig": "^0.15.17" }, "bin": { "cssx": "./dist/bin/cssx.js", "ts-css": "./dist/bin/cli.js" } }, "sha512-ndEmNAQhDEphIrCZPnK0GVAj6JNGLWlNtSptppbTdU2sFtX+ptXYkZAUIqBglbmYuqJObda3yjs5Y09Zv7Swlg=="], | |
| 247 | "@stacksjs/ts-css": ["@stacksjs/ts-css@0.3.16", "", { "dependencies": { "@stacksjs/clapp": "^0.2.0", "bunfig": "^0.15.17" }, "bin": { "cssx": "./dist/bin/cssx.js", "ts-css": "./dist/bin/cli.js" } }, "sha512-V51ejGqHrK/ACC/JPVgiit0ol8QSERJYR3Hdf7kLV0gRkOHd5GHtPvXKpzCGJKFLwpW/hEEKGnkDYC5ZypkUkg=="], | |
| 248 | 248 | |
| 249 | 249 | "@stacksjs/ts-faker": ["@stacksjs/ts-faker@0.1.8", "", { "dependencies": { "@stacksjs/clapp": "^0.2.0" }, "bin": { "@stacksjs/ts-faker": "dist/bin/cli.js", "faker": "dist/bin/cli.js", "fake": "dist/bin/cli.js", "mock": "dist/bin/cli.js" } }, "sha512-YEOIr9mlMeXodcl8FmX3Rq7fqZDcubi7nwdl7lCKr682GIimOQjdN8miQmVEgbBYlpwP1cOn8eO6DhVotMwWnw=="], |
| 250 | 250 | |
| @@ -1,44 +1,37 @@ | ||
| 1 | 1 | /** |
| 2 | * The reduced-motion guard on the account skeleton, and the spelling that | |
| 3 | * silently cannot provide one. | |
| 2 | * The reduced-motion guard on the account skeleton. | |
| 4 | 3 | * |
| 5 | 4 | * account.stx used to carry `motion-reduce:[animation:none]` beside an |
| 6 | * `[animation:loghq-pulse_…]` utility. The animation worked; the guard never | |
| 7 | * did. Crosswind's class EXTRACTOR does not recognise a variant applied to an | |
| 5 | * `[animation:loghq-pulse_...]` utility. The animation worked; the guard never | |
| 6 | * did. Crosswind's class EXTRACTOR did not recognise a variant applied to an | |
| 8 | 7 | * arbitrary property, so that class never reached the generator and produced |
| 9 | 8 | * no rule at all -- no error, no warning, nothing in the sheet. Measured on |
| 10 | 9 | * the served page: every other class on that element reached the stylesheet |
| 11 | 10 | * and this one did not, while `active:` and `md:` rules from the same page |
| 12 | * were present, so plain variants are fine. | |
| 11 | * were present, so plain variants were fine. | |
| 13 | 12 | * |
| 14 | * Filed as stacksjs/ts-css#37. The generator half was fixed in 0.3.14 | |
| 15 | * (ts-css#36); the extractor half is open, so the spelling is still a trap. | |
| 13 | * **That extractor bug is FIXED** (stacksjs/ts-css#37, in 0.3.16, which this | |
| 14 | * app now runs; the generator half was #36 in 0.3.14). Probed against this | |
| 15 | * app's own installed copy with the exact original spelling: | |
| 16 | * `motion-reduce:[animation:none]` extracts and emits | |
| 17 | * `@media (prefers-reduced-motion: reduce) { .motion-reduce\:\[animation\:none\] | |
| 18 | * { animation: none } }`. So the spelling is no longer a trap, and the test | |
| 19 | * that failed any view for using it has been removed. | |
| 16 | 20 | * |
| 17 | * Both halves now live in public/tokens.css instead, in source order, which | |
| 18 | * is what makes the guard independent of the extractor, of crosswind's output | |
| 19 | * ordering and of any !important. That file is also linked BEFORE the | |
| 20 | * generated sheet, which is why the animation itself moved there rather than | |
| 21 | * Both halves still live in public/tokens.css, in source order, and that is | |
| 22 | * still the better home: as utilities the two rules tie on specificity and | |
| 23 | * the guard wins only because the generator happens to emit the media query | |
| 24 | * second. tokens.css makes the order explicit, and it is linked BEFORE the | |
| 25 | * generated sheet, which is why the animation moved there too rather than | |
| 21 | 26 | * staying a utility for the guard to fight. |
| 22 | 27 | */ |
| 23 | 28 | import { describe, expect, test } from 'bun:test' |
| 24 | import { readdirSync, readFileSync, statSync } from 'node:fs' | |
| 29 | import { readFileSync } from 'node:fs' | |
| 25 | 30 | import { join } from 'node:path' |
| 26 | 31 | |
| 27 | 32 | const ROOT = join(import.meta.dir, '../..') |
| 28 | 33 | const tokens = readFileSync(join(ROOT, 'public/tokens.css'), 'utf8') |
| 29 | 34 | |
| 30 | function stxFiles(dir: string): string[] { | |
| 31 | const out: string[] = [] | |
| 32 | for (const entry of readdirSync(dir)) { | |
| 33 | const full = join(dir, entry) | |
| 34 | if (statSync(full).isDirectory()) | |
| 35 | out.push(...stxFiles(full)) | |
| 36 | else if (entry.endsWith('.stx')) | |
| 37 | out.push(full) | |
| 38 | } | |
| 39 | return out | |
| 40 | } | |
| 41 | ||
| 42 | 35 | describe('reduced motion', () => { |
| 43 | 36 | test('the skeleton declares its animation and its guard, in that order', () => { |
| 44 | 37 | const base = tokens.search(/\.skeleton-pulse\s*\{/) |
| @@ -58,21 +51,4 @@ describe('reduced motion', () => { | ||
| 58 | 51 | // guard on source order while tying on specificity. |
| 59 | 52 | expect(account).not.toMatch(/\[animation:loghq-pulse/) |
| 60 | 53 | }) |
| 61 | ||
| 62 | test('no view uses a variant on an arbitrary property', () => { | |
| 63 | /* | |
| 64 | * `motion-reduce:[animation:none]`, `hover:[border-color:red]` and friends. | |
| 65 | * They parse, they look right, and they emit nothing. Worth failing a test | |
| 66 | * over precisely because nothing else reports it -- and the cases people | |
| 67 | * reach for this spelling are the accessibility and edge-state ones, which | |
| 68 | * are the least likely to be noticed by eye. | |
| 69 | * | |
| 70 | * Drop this when ts-css#37 closes and the extractor can see them. | |
| 71 | */ | |
| 72 | for (const file of stxFiles(join(ROOT, 'resources'))) { | |
| 73 | const source = readFileSync(file, 'utf8').replace(/\{\{--[\s\S]*?--\}\}/g, '') | |
| 74 | const hit = /[a-z-]+:\[[a-z-]+:[^\]]*\]/.exec(source) | |
| 75 | expect(`${file.slice(ROOT.length + 1)}: ${hit ? hit[0] : 'none'}`).toBe(`${file.slice(ROOT.length + 1)}: none`) | |
| 76 | } | |
| 77 | }) | |
| 78 | 54 | }) |