feat(foundry): refine map application controls

This commit is contained in:
Codex
2026-08-09 14:24:18 +03:00
parent 7025fd20b5
commit beb84f6de6
18 changed files with 633 additions and 186 deletions
@@ -39,6 +39,34 @@ test("Map Inspector open section is controlled and included in the saved page la
assert.match(manifestSchema, /"inspectorOpenSections"[\s\S]*?"maxItems": 1/);
});
test("Map settings use a canonical trailing push panel and ApplicationPanel header actions", async () => {
const [shell, panel, inspector, preview, catalog, styles, catalogStyles] = await Promise.all([
readFile(new URL("../packages/ui-react/src/ApplicationShell.tsx", import.meta.url), "utf8"),
readFile(new URL("../packages/ui-react/src/ApplicationSidePanel.tsx", import.meta.url), "utf8"),
readFile(new URL("../packages/ui-react/src/Inspector.tsx", import.meta.url), "utf8"),
readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8"),
readFile(new URL("../apps/catalog/src/CatalogApp.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"),
]);
assert.match(shell, /endPanelOpen\?: boolean/);
assert.match(shell, /nodedc-app-shell__end-panel/);
assert.match(panel, /data-placement="end"/);
assert.doesNotMatch(panel, /pinned|onPinnedChange|Icon name="pin"/);
assert.match(inspector, /variant\?: "default" \| "panel"/);
assert.match(preview, /createPortal\(settingsPanel, settingsPanelHost\)/);
assert.match(preview, /createPortal\(headerActions, headerActionsHost\)/);
assert.match(preview, /variant="panel"/);
assert.doesNotMatch(preview, /settingsPanelPinned|onPointerDownCapture/);
assert.match(catalog, /endPanelOpen=\{mapSettingsPanelOpen\}/);
assert.match(catalog, /headerTools=\{activePageTemplate\.id === "map"[\s\S]*?setMapHeaderActionsHost/);
assert.match(styles, /data-content-expanded="true"\]\[data-end-panel-open="true"\][\s\S]*?right: calc\(/);
assert.match(styles, /@keyframes nodedc-application-side-panel-in[\s\S]*?translateX\(1\.6rem\)/);
assert.match(catalogStyles, /\.catalog-map-header-action\.nodedc-icon-button[\s\S]*?--nodedc-panel-action-bg/);
assert.match(catalogStyles, /\.catalog-map-header-action\.nodedc-icon-button\[data-active="true"\][\s\S]*?--nodedc-glass-control-active/);
});
test("canonical station profiles retain visible target borders while label text stays halo-free", async () => {
const registry = JSON.parse(await readFile(
new URL("../registry/map-presentation-profiles.json", import.meta.url),
+21 -4
View File
@@ -37,16 +37,33 @@ test("joined detail aspects do not become independent map layers", async () => {
assert.match(preview, /runtimeBindings=\{\[\.\.\.sectorScopedPrimaryRuntimeBindings, \.\.\.referenceRuntimeBindings\]\}/);
});
test("map windows share one bounded activation and z-index stack", async () => {
test("bounded map windows keep one stack while layers and settings use their canonical surfaces", async () => {
const preview = await readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8");
assert.match(preview, /type MapWorkspaceWindowId = "settings" \| "layers" \| "sector" \| "subject-card" \| `binding:\$\{string\}`/);
assert.match(preview, /type MapWorkspaceWindowId = "sector" \| "subject-card" \| `binding:\$\{string\}`/);
assert.match(preview, /const activateWorkspaceWindow = useCallback/);
assert.match(preview, /settingsWindowZIndex[\s\S]*layersWindowZIndex[\s\S]*sectorWindowZIndex[\s\S]*subjectCardZIndex/);
assert.match(preview, /title="Настройки карты"[\s\S]*active=\{activeWorkspaceWindowId === "settings"\}/);
assert.match(preview, /sectorWindowZIndex[\s\S]*subjectCardZIndex/);
assert.match(preview, /<ApplicationSidePanel[\s\S]*title="Настройки карты"[\s\S]*onClose=\{closeSettingsPanel\}/);
assert.match(preview, /createPortal\(headerActions, headerActionsHost\)/);
assert.doesNotMatch(preview, /settingsPanelPinned|onPinnedChange/);
assert.match(preview, /surfaceClassName="catalog-map-fixture__objects-menu catalog-map-fixture__layers-menu nodedc-map-glass"/);
assert.match(preview, /onOpenChange=\{setLayersOpen\}/);
assert.doesNotMatch(preview, /settingsWindowZIndex|layersWindowZIndex/);
assert.doesNotMatch(preview, /<Window\b/);
});
test("selecting a point or HGeoZone preserves the active grid sector", async () => {
const renderer = await readFile(new URL("../apps/catalog/src/CesiumMapRenderer.tsx", import.meta.url), "utf8");
const pointBranch = renderer.match(/if \(pickedId instanceof Entity[\s\S]*?return;\s*\}/)?.[0] ?? "";
const zoneBranch = renderer.match(/if \(\s*pickedId[\s\S]*?HGeoZonePickId\)\.entityId\);\s*return;\s*\}/)?.[0] ?? "";
assert.match(pointBranch, /onSelectRef\.current\?\.\(pickedId\.id\)/);
assert.match(zoneBranch, /onSelectRef\.current\?\.\(\(pickedId as HGeoZonePickId\)\.entityId\)/);
assert.doesNotMatch(pointBranch, /setSelection\(null\)|onGridSectorSelectRef\.current\?\.\(null\)/);
assert.doesNotMatch(zoneBranch, /setSelection\(null\)|onGridSectorSelectRef\.current\?\.\(null\)/);
assert.match(renderer, /gridController\?\.setSelection\(gridSelection\);\s*onGridSectorSelectRef\.current\?\.\(gridSelection\)/);
});
test("an active sector scopes point facts, exposes data facets and deactivates on close", async () => {
const preview = await readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8");