Files
BlackVortexAI 8e73c79853 Centralize BV node presentation and regional UI infrastructure
- unify presentation lifecycle, port projection, and native node sizing
- add Regional Canvas image sources and the shared compact image picker
- align LoRA Registry outputs and 0.05 strength scrubbing
- retain the titlebar-port Canary as branch-only experiment evidence

Validated: 458 Python tests, 655 Node tests, TypeScript typecheck, compileall, production build, staged bundle match, and secret scan.

The titlebar-port Canary is throw-away experiment code and must be removed before merge or release.
2026-08-31 21:01:51 +02:00

69 lines
4.5 KiB
JavaScript

import assert from"node:assert/strict";
import{readFileSync}from"node:fs";
import test from"node:test";
import React from"../ui/node_modules/react/index.js";
import{renderToStaticMarkup}from"../ui/node_modules/react-dom/server.node.js";
import{ImagePicker,ImagePickerOptionRow,ImagePickerOptions,imageOptionPreviewSource,imageOptionSource}from"../ui/src/ui/components/data.tsx";
const styles=readFileSync(new URL("../ui/src/index.css",import.meta.url),"utf8");
const ruleBody=selector=>{
const start=styles.lastIndexOf(`${selector} {`);
assert.notEqual(start,-1,`missing CSS rule: ${selector}`);
return styles.slice(styles.indexOf("{",start)+1,styles.indexOf("}",start));
};
const escapeRegExp=value=>value.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");
const hasDeclaration=(body,property,value)=>assert.match(body,new RegExp(`${property}\\s*:\\s*${escapeRegExp(value)}`));
test("shared image picker preserves defaults and renders a real thumbnail",()=>{
const option={id:"one",name:"Sender 1",meta:"Latest",src:"/full.png",thumbnail:"/thumb.png"};
const markup=renderToStaticMarkup(React.createElement(ImagePicker,{label:"Queue image",value:"one",onValue(){},options:[option]}));
assert.match(markup,/bv-control-label/);assert.match(markup,/src="\/thumb.png"/);assert.doesNotMatch(markup,/src="\/full.png"/);assert.match(markup,/Open large preview/);
assert.equal(imageOptionSource(option),"/thumb.png");assert.equal(imageOptionPreviewSource(option),"/full.png");
});
test("shared image picker supports compact accessible no-image selections",()=>{
const markup=renderToStaticMarkup(React.createElement(ImagePicker,{className:"feature-picker",label:"Canvas image",labelVisible:false,largePreview:false,value:"missing",onValue(){},options:[{id:"missing",name:"Source unavailable",disabled:true}]}));
assert.match(markup,/feature-picker/);assert.match(markup,/aria-label="Canvas image"/);assert.match(markup,/bv-image-picker-placeholder/);assert.doesNotMatch(markup,/<img/);assert.doesNotMatch(markup,/bv-image-preview-action/);
});
test("shared image picker options enforce disabled selection and accessibility",()=>{
const option={id:"missing",name:"Source unavailable",disabled:true};let selected="";
const row=ImagePickerOptionRow({item:option,selected:true,onSelect:id=>{selected=id}});
assert.equal(row.props.role,"option");assert.equal(row.props["aria-selected"],true);assert.equal(row.props.disabled,true);
row.props.onClick();assert.equal(selected,"");
const markup=renderToStaticMarkup(React.createElement(ImagePickerOptions,{label:"Canvas image",options:[option],value:"missing",onSelect:id=>{selected=id}}));
assert.match(markup,/role="listbox"/);assert.match(markup,/role="option"/);assert.match(markup,/aria-selected="true"/);assert.match(markup,/disabled=""/);assert.match(markup,/aria-hidden="true"/);
});
test("shared image picker contains long option labels inside menu and trigger",()=>{
const longName="Prompt #54bv_regional_canvas_temp_nnzpy_00001_png_with_an_extremely_long_source_name";
const markup=renderToStaticMarkup(React.createElement(ImagePicker,{label:"Canvas image",value:"long",onValue(){},options:[{id:"long",name:"Prompt",meta:longName}]}));
assert.match(markup,new RegExp(longName));
const listbox=ruleBody('.bv-image-picker-menu [role=listbox]');
hasDeclaration(listbox,"grid-template-columns","minmax(0,1fr)");
hasDeclaration(listbox,"min-width","0");
hasDeclaration(listbox,"max-width","100%");
const row=ruleBody('.bv-image-picker-menu [role=listbox]>button');
hasDeclaration(row,"box-sizing","border-box");
hasDeclaration(row,"min-width","0");
hasDeclaration(row,"max-width","100%");
hasDeclaration(row,"overflow","hidden");
const optionText=ruleBody('.bv-image-picker-menu [role=listbox]>button>span');
hasDeclaration(optionText,"flex","1 1 auto");
hasDeclaration(optionText,"min-width","0");
hasDeclaration(optionText,"overflow","hidden");
const triggerText=ruleBody('.bv-image-picker-trigger>span');
hasDeclaration(triggerText,"min-width","0");
hasDeclaration(triggerText,"overflow","hidden");
for(const selector of['.bv-image-picker-menu [role=listbox]>button>span>strong,.bv-image-picker-menu [role=listbox]>button>span>small','.bv-image-picker-trigger>span>strong,.bv-image-picker-trigger>span>small']){
const label=ruleBody(selector);
hasDeclaration(label,"display","block");
hasDeclaration(label,"overflow","hidden");
hasDeclaration(label,"text-overflow","ellipsis");
hasDeclaration(label,"white-space","nowrap");
}
});