Pin sceneButtons folds recipe classes to the installed folds (#111)
All checks were successful
Rat dev preview / Build dev preview (push) Successful in 4m6s

This commit is contained in:
Void 2026-11-12 09:51:15 +00:00
commit 07b82f2477
2 changed files with 40 additions and 10 deletions

View file

@ -2,9 +2,14 @@ import { globalStyle } from '@vanilla-extract/css';
// Meta, 2026-11-10: "buttons are big and ugly, too, they don't need chrome either". Over the scene a folds Button or
// Chip is its label in the page's ink, with a faint wash on hover and focus. Menus and dialogs (#portalContainer) keep
// folds' look. The selectors are folds' hashed recipe base classes (Button epr39zd, Chip _1bv8u1w6).
// folds' look. The selectors are folds' hashed recipe base classes (Button, Chip; pinned below).
// sceneButtons.test.ts resolves both from the installed folds and fails when a folds upgrade rehashes them.
export const FOLDS_BUTTON_CLASS = 'epr39zd';
export const FOLDS_CHIP_CLASS = '_1bv8u1w6';
const scene = ':root[data-scene] #root';
const controls = [`${scene} .epr39zd`, `${scene} ._1bv8u1w6`].join(', ');
const btn = `${scene} .${FOLDS_BUTTON_CLASS}`;
const chip = `${scene} .${FOLDS_CHIP_CLASS}`;
const controls = [btn, chip].join(', ');
globalStyle(controls, {
backgroundColor: 'transparent',
boxShadow: 'none',
@ -12,20 +17,15 @@ globalStyle(controls, {
color: 'inherit',
});
globalStyle(
[
`${scene} .epr39zd:hover`,
`${scene} .epr39zd:focus-visible`,
`${scene} ._1bv8u1w6:hover`,
`${scene} ._1bv8u1w6:focus-visible`,
].join(', '),
[`${btn}:hover`, `${btn}:focus-visible`, `${chip}:hover`, `${chip}:focus-visible`].join(', '),
{ backgroundColor: 'color-mix(in srgb, currentColor 12%, transparent)' }
);
// A visible keyboard focus ring in the control's own ink, on top of the hover wash.
globalStyle([`${scene} .epr39zd:focus-visible`, `${scene} ._1bv8u1w6:focus-visible`].join(', '), {
globalStyle([`${btn}:focus-visible`, `${chip}:focus-visible`].join(', '), {
outline: '2px solid currentColor',
outlineOffset: '2px',
});
globalStyle(`${scene} .epr39zd`, {
globalStyle(btn, {
fontWeight: 700,
textDecoration: 'underline',
textUnderlineOffset: '0.25em',

View file

@ -0,0 +1,30 @@
import { readFileSync } from 'fs';
import { createRequire } from 'module';
import { dirname, join } from 'path';
import { describe, expect, it } from 'vitest';
// sceneButtons.css.ts restyles folds' Button and Chip by their hashed recipe base classes. A folds upgrade rehashes
// them and the chromeless buttons would silently revert, so resolve the classes from the installed folds.
const foldsDir = dirname(createRequire(import.meta.url).resolve('folds/package.json'));
const dist = readFileSync(join(foldsDir, 'dist/index.js'), 'utf8');
const css = readFileSync(join(foldsDir, 'dist/style.css'), 'utf8');
const sceneButtons = readFileSync(
`${process.cwd()}/src/app/features/scene/sceneButtons.css.ts`,
'utf8'
);
const recipeBase = (name: string) =>
new RegExp(`\\b${name}\\$1 = createRuntimeFn\\(\\{ defaultClassName: "([^" ]+)`).exec(dist)?.[1];
const pinned = (name: string) => new RegExp(`${name} = '([^']+)'`).exec(sceneButtons)?.[1];
describe('sceneButtons pins folds recipe base classes', () => {
it.each([
['Button', 'FOLDS_BUTTON_CLASS'],
['Chip', 'FOLDS_CHIP_CLASS'],
])('%s base class matches the installed folds', (recipe, constant) => {
const base = recipeBase(recipe);
expect(base, `folds no longer builds ${recipe} with createRuntimeFn`).toBeTruthy();
expect(pinned(constant)).toBe(base);
expect(css).toContain(`.${base} {`);
});
});