Install ReUI (MCP, skill, @reui registry, Tailwind v4, shadcn base-nova) and move the shared UI onto it: Button, Tag, Check, Input/Textarea, Segmented, Alert, Panel, Dialog, Tooltip, Menu and Select (Popover), Toast (sonner), the Table frame (DataGrid), the Dashboard KPI strip, the shnt Ops palette, Geist and the type scale. Design only: behaviour, texts and roles are unchanged. Tests that asserted the old DOM were updated; the tests now format numbers in English wherever they run. docs/reui-migration-plan.md records the plan and its decisions. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
89 lines
3.5 KiB
JavaScript
89 lines
3.5 KiB
JavaScript
/*
|
|
The raw-output rules that live only in the CSS.
|
|
|
|
jsdom does not apply CSS modules, so no render test can see `white-space` or
|
|
`max-height`, and those are the two decisions this primitive exists to take. It
|
|
lives in `dev/` and not under `src/` for the same reason as
|
|
`master-switch-signal.test.mjs`: reading files needs `node:fs`, and everything
|
|
under `src/` compiles without node's types. A `node:fs` there passes the suite and
|
|
breaks the build.
|
|
*/
|
|
import { describe, expect, it } from 'vitest'
|
|
import { readFileSync } from 'node:fs'
|
|
import { dirname, resolve } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const css = readFileSync(
|
|
resolve(dirname(fileURLToPath(import.meta.url)), '../src/ui/Raw.module.css'),
|
|
'utf8',
|
|
)
|
|
const rule = (n) => /* that class's declaration block */ new RegExp(`\\.${n}\\s*\\{([^}]*)\\}`).exec(css)?.[1] ?? ''
|
|
|
|
describe('raw output does not wrap', () => {
|
|
const text = rule('text')
|
|
|
|
/*
|
|
THE decision of this pattern. The two places where it was written before used
|
|
`pre-wrap` with `word-break`, and that breaks the one thing that makes a long
|
|
JSON readable: the indentation. The price is a horizontal scroll bar.
|
|
*/
|
|
it('it uses `pre` and not `pre-wrap`', () => {
|
|
expect(text).toMatch(/white-space:\s*pre\s*;/)
|
|
expect(text).not.toMatch(/pre-wrap/)
|
|
expect(text).not.toMatch(/word-break/)
|
|
})
|
|
|
|
it('it scrolls on both axes and does not drag the page', () => {
|
|
expect(text).toMatch(/overflow:\s*auto/)
|
|
expect(text).toMatch(/overscroll-behavior:\s*contain/)
|
|
})
|
|
|
|
/* The panel does not grow with the content: measured, the viewer once loaded
|
|
1,073,928 characters. */
|
|
it('has a height cap, set through a variable so each use can fix its own', () => {
|
|
expect(text).toMatch(/max-height:\s*var\(--raw-height/)
|
|
})
|
|
|
|
/* The border goes on the box: on the element that scrolls, it would move with
|
|
the horizontal scroll. */
|
|
it('the border lives on the box and not on the text', () => {
|
|
expect(rule('box')).toMatch(/border:/)
|
|
expect(text).not.toMatch(/border:/)
|
|
})
|
|
})
|
|
|
|
/*
|
|
The two modifiers View Logs asks for. Neither may leak into the default above, and
|
|
neither may cut a word letter by letter (`npm run lint:breaks`).
|
|
*/
|
|
describe('raw output, when the caller asks it to wrap or to fill', () => {
|
|
it('`wrap` soft-wraps with a hanging indent read from `--raw-hang`', () => {
|
|
const wrap = rule('wrap')
|
|
expect(wrap).toMatch(/white-space:\s*pre-wrap/)
|
|
expect(wrap).toMatch(/text-indent:\s*var\(--raw-hang[^;]*\)\s*hanging\s+each-line/)
|
|
})
|
|
|
|
/* `break-word` cuts only a piece wider than the whole box; `anywhere` and
|
|
`break-all` would end lines inside words wherever the edge falls. */
|
|
it('`wrap` breaks between words, never anywhere', () => {
|
|
const wrap = rule('wrap')
|
|
expect(wrap).toMatch(/overflow-wrap:\s*break-word/)
|
|
expect(wrap).not.toMatch(/anywhere|break-all|word-break/)
|
|
})
|
|
|
|
it('on a phone the indent drops to two characters', () => {
|
|
expect(css).toMatch(/@media \(max-width: 560px\)\s*\{\s*\.wrap\s*\{\s*text-indent:\s*2ch hanging each-line;/)
|
|
})
|
|
|
|
/* Out of flow, so the file adds nothing to the page's height; the box's
|
|
`min-height` is the floor. */
|
|
it('`fill` lays the text out of flow over a box with a floor', () => {
|
|
expect(rule('fill')).toMatch(/min-height:\s*var\(--raw-height/)
|
|
expect(rule('fill')).toMatch(/flex:\s*1 1 auto/)
|
|
const inner = /\.fill\s*>\s*\.text\s*\{([^}]*)\}/.exec(css)?.[1] ?? ''
|
|
expect(inner).toMatch(/position:\s*absolute/)
|
|
expect(inner).toMatch(/inset:\s*0/)
|
|
expect(inner).toMatch(/max-height:\s*none/)
|
|
})
|
|
})
|