98 lines
4.1 KiB
JavaScript
98 lines
4.1 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import test from "node:test";
|
|
|
|
import { computeFloatingPosition } from "../packages/ui-core/dist/index.js";
|
|
|
|
test("floating surface remains bounded when its anchor is above the viewport", () => {
|
|
const position = computeFloatingPosition({
|
|
anchor: {
|
|
top: -1888,
|
|
right: 1228,
|
|
bottom: -1842,
|
|
left: 940,
|
|
width: 288,
|
|
height: 46,
|
|
},
|
|
surfaceWidth: 324,
|
|
surfaceHeight: 144,
|
|
viewportWidth: 1280,
|
|
viewportHeight: 720,
|
|
viewportPadding: 8,
|
|
});
|
|
|
|
assert.equal(position.top, 8);
|
|
assert.ok(position.maxHeight <= 704);
|
|
assert.ok(position.maxHeight >= 0);
|
|
});
|
|
|
|
test("floating surface remains bounded when its anchor is below the viewport", () => {
|
|
const position = computeFloatingPosition({
|
|
anchor: {
|
|
top: 1200,
|
|
right: 640,
|
|
bottom: 1246,
|
|
left: 320,
|
|
width: 320,
|
|
height: 46,
|
|
},
|
|
surfaceWidth: 320,
|
|
surfaceHeight: 500,
|
|
viewportWidth: 1280,
|
|
viewportHeight: 720,
|
|
viewportPadding: 8,
|
|
});
|
|
|
|
assert.ok(position.top >= 8);
|
|
assert.ok(position.top + Math.min(500, position.maxHeight) <= 712);
|
|
assert.ok(position.maxHeight <= 704);
|
|
});
|
|
|
|
test("dropdown scroll keeps portal geometry stable and contained", async () => {
|
|
const styles = await readFile(
|
|
new URL("../packages/ui-core/styles.css", import.meta.url),
|
|
"utf8",
|
|
);
|
|
const dropdownRule = styles.match(/\.nodedc-dropdown-surface \{(?<body>[\s\S]*?)\n\}/)?.groups?.body ?? "";
|
|
|
|
assert.match(dropdownRule, /box-sizing:\s*border-box;/);
|
|
assert.match(dropdownRule, /overflow:\s*auto;/);
|
|
assert.match(dropdownRule, /overscroll-behavior:\s*contain;/);
|
|
});
|
|
|
|
test("workspace windows keep their glass rim without masked compositor overlays", async () => {
|
|
const [workspace, styles, mapStyles] = await Promise.all([
|
|
readFile(new URL("../packages/ui-react/src/WorkspaceWindow.tsx", import.meta.url), "utf8"),
|
|
readFile(new URL("../packages/ui-core/styles.css", import.meta.url), "utf8"),
|
|
readFile(new URL("../apps/catalog/src/styles.css", import.meta.url), "utf8"),
|
|
]);
|
|
const rootClass = workspace.match(/className=\{cn\("(?<classes>[^"]+)"/)?.groups?.classes ?? "";
|
|
const windowRule = styles.match(/\.nodedc-workspace-window \{(?<body>[\s\S]*?)\n\}/)?.groups?.body ?? "";
|
|
const materialOverride = styles.match(/\.nodedc-workspace-window\.nodedc-glass-material::before \{(?<body>[\s\S]*?)\n\}/)?.groups?.body ?? "";
|
|
const mapWindowRule = mapStyles.match(/\.catalog-map-fixture__map-glass-window \{(?<body>[\s\S]*?)\n\}/)?.groups?.body ?? "";
|
|
|
|
assert.match(rootClass, /\bnodedc-glass-material\b/);
|
|
assert.doesNotMatch(rootClass, /\bnodedc-material-rim\b/);
|
|
assert.match(windowRule, /box-sizing:\s*border-box;/);
|
|
assert.match(windowRule, /border:\s*1px solid;/);
|
|
assert.match(windowRule, /border-color:[\s\S]*--nodedc-modal-glass-outline-opacity/);
|
|
assert.match(materialOverride, /content:\s*none;/);
|
|
assert.doesNotMatch(materialOverride, /mask/);
|
|
assert.match(mapWindowRule, /backdrop-filter:\s*none;/);
|
|
assert.match(mapWindowRule, /contain:\s*layout paint;/);
|
|
assert.doesNotMatch(mapWindowRule, /backdrop-filter:\s*blur/);
|
|
});
|
|
|
|
test("workspace pointer drag paints on animation frames and commits once on release", async () => {
|
|
const workspace = await readFile(new URL("../packages/ui-react/src/WorkspaceWindow.tsx", import.meta.url), "utf8");
|
|
const pointerMove = workspace.match(/const handlePointerMove = \(event: globalThis\.PointerEvent\) => \{(?<body>[\s\S]*?)\n \};/)?.groups?.body ?? "";
|
|
const pointerEnd = workspace.match(/const endInteraction = \(event: globalThis\.PointerEvent\) => \{(?<body>[\s\S]*?)\n \};/)?.groups?.body ?? "";
|
|
|
|
assert.match(workspace, /interactionFrameRef\.current = window\.requestAnimationFrame\(paintInteraction\)/);
|
|
assert.match(pointerMove, /interaction\.previewRect = nextRect/);
|
|
assert.match(pointerMove, /scheduleInteractionPaint\(\)/);
|
|
assert.doesNotMatch(pointerMove, /onRectChangeRef|emitRect/);
|
|
assert.match(pointerEnd, /onRectChangeRef\.current\(nextRect\)/);
|
|
assert.match(workspace, /translate3d\(\$\{deltaX\}px, \$\{deltaY\}px, 0\)/);
|
|
});
|