Files
adminandClaude Opus 5.5 a848cf8469
game-maker / gate (push) Successful in 3m48s
game-maker / suite (push) Successful in 15m0s
Pick a new asset from category submenus in the + menu
The + menu was one long list in two groups, placeable types and
library ones. That split is no longer wanted. The menu now lists the
categories of the asset panel, and each opens its types beside it, so
a new asset is filed where the panel shows it.

- Menu learns submenus: an entry with submenu instead of onSelect
  opens a second Menu right of the first, or left of it where the
  canvas ends. Its first entry lines up with the row that opened it.
- A submenu opens on hover or click. Resting on another entry swaps
  or closes it after 150 ms, so a pointer cutting across the rows on
  its way into a submenu does not lose it.
- The row of an open submenu stays lit, and a triangle pointing right
  marks every such row.
- A submenu has no backdrop and no Escape of its own. Popup takes a
  backdrop option for that. The first menu's backdrop and Escape
  close the whole stack, and picking an entry does the same.
- assetMenuCategories replaces assetMenuGroups and takes categories
  and their order from ASSET_GROUPS. The types are sorted by label.
- New test hooks __gm.menuSubmenus() and __gm.addMenuCategory().
  pickAssetType opens the category first, so the modules that pick a
  type through it need no change of their own. Modules 04, 10, 47,
  48, 53 and 54 open the category themselves where they read the menu.

Tests:
- Unit asset-menu: 4 green
- e2e 04: ALL PASSED, 63 checks. New: categories in panel order, each
  type once and sorted, submenu placement, hover swaps the submenu,
  picking closes menu and submenu
- Gate: CHECK EXIT 0, 261 files, 4040 tests
- The other modules that use the + menu did not run here

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 18:17:21 +02:00

32 lines
1.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest';
import { ASSET_TYPE_LABELS, ASSET_TYPES, type AssetType } from '../../src/core/model/AssetTypes';
import { ASSET_CATEGORIES, ASSET_GROUPS } from '../../src/editor/panels/assetGroups';
import { assetMenuCategories } from '../../src/editor/panels/assetMenu';
const labels = (types: AssetType[]) => types.map((type) => ASSET_TYPE_LABELS[type]);
describe('assetMenuCategories', () => {
it('offers every type exactly once', () => {
const flat = assetMenuCategories().flatMap((entry) => entry.types);
expect([...flat].sort()).toEqual([...ASSET_TYPES].sort());
});
it('files every type under the category the asset panel shows it in, in the panel order', () => {
const menu = assetMenuCategories();
expect(menu.map((entry) => entry.category)).toEqual([...ASSET_CATEGORIES]);
for (const { category, types } of menu)
expect(types.every((type) => ASSET_GROUPS[type].category === category)).toBe(true);
});
it('sorts each category by label, not by declaration order', () => {
for (const { types } of assetMenuCategories()) expect(labels(types)).toEqual([...labels(types)].sort());
// Declaration order has Camera after Scene; by label it comes first.
expect(assetMenuCategories()[0]!.types.slice(0, 2)).toEqual(['camera', 'container']);
});
it('leaves ASSET_TYPES alone – it is also the serialisation order', () => {
assetMenuCategories();
expect(ASSET_TYPES[0]).toBe('scene');
});
});