Lay out a scroll container's content when the content changes
A short list opened after a long one drew all its rows stacked on one point. The fault was not in the list tab: rebuild() handed the row stack to setContent() while it was still empty, so the content was sized to max(rows, viewport) = the viewport. The rows arrived after that, and for a short list the same formula yields the same height, so resize() saw no change and skipped layout(). A long list changes the height and never showed it. relayoutContent() now runs whenever the content changed, rather than leaning on resize()'s change detection - that detection is the wrong instrument for "the children moved". The list tab was the only affected caller: the panels use ListView, which positions its rows itself, and the inspector fills its body before setContent. Also drops the comma line under the list. Every section that can carry a list supplies openList, so the comma fallback in fieldFactory was unreachable; listToText/listFromText go with it. The list-value test now covers coerceListItem through coerceValue instead, so the boolean spelling stays guarded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e52e95c0e9
commit
4d07946c74
9 files changed
+102
-87
No files matched your search
+26
-3
@@ -52,7 +52,30 @@ export async function listTab(t) {
|
||||
info = await json('__gm.list.info()');
|
||||
check('undo takes just that item back', JSON.stringify(info.items) === '["30","11","44"]', info.items[1]);
|
||||
|
||||
// 4. Adding and removing whole items.
|
||||
// 4. A short list opened after a long one. Its rows leave the content height pinned to the
|
||||
// viewport, so a layout skipped on "same size" would stack them all at the top.
|
||||
await mutate(`
|
||||
const a = __gm.state.project.assets.find((x) => x.id === 'listy');
|
||||
a.props.nums = Array.from({ length: 60 }, (_, i) => i);
|
||||
__gm.state.preview();
|
||||
`);
|
||||
await sleep(250);
|
||||
const longRows = [await json('__gm.list.fieldAt(0)'), await json('__gm.list.fieldAt(1)')];
|
||||
check('a long list stacks its rows', longRows[0].y !== longRows[1].y, JSON.stringify(longRows));
|
||||
await mutate(`
|
||||
const a = __gm.state.project.assets.find((x) => x.id === 'listy');
|
||||
a.props.nums = [30, 11, 44];
|
||||
__gm.state.preview();
|
||||
`);
|
||||
await sleep(250);
|
||||
const shortRows = [await json('__gm.list.fieldAt(0)'), await json('__gm.list.fieldAt(1)')];
|
||||
check(
|
||||
'and a short list after it still stacks its own',
|
||||
shortRows[0].y !== shortRows[1].y,
|
||||
JSON.stringify(shortRows),
|
||||
);
|
||||
|
||||
// 5. Adding and removing whole items.
|
||||
await clickText('+ Item');
|
||||
await sleep(200);
|
||||
info = await json('__gm.list.info()');
|
||||
@@ -61,7 +84,7 @@ export async function listTab(t) {
|
||||
check('undo removes it again', (await json('__gm.list.info()')).items.length === 3);
|
||||
await shot('03-rows');
|
||||
|
||||
// 5. Back on the scene tab the button carries the current count.
|
||||
// 6. Back on the scene tab the button carries the current count.
|
||||
await mutate('__gm.state.openList(null)');
|
||||
await sleep(200);
|
||||
check('closing the list leaves the tab', (await json('__gm.tab()')) === 'scene');
|
||||
@@ -72,7 +95,7 @@ export async function listTab(t) {
|
||||
await sleep(200);
|
||||
check('and the count follows the value', (await find('2 items')) !== null);
|
||||
|
||||
// 6. A list whose target is gone empties the tab rather than showing a stale one.
|
||||
// 7. A list whose target is gone empties the tab rather than showing a stale one.
|
||||
await mutate("__gm.state.openList({ kind: 'asset', assetId: 'listy', key: 'nums' })");
|
||||
await sleep(200);
|
||||
check('a list can be opened from outside the inspector too', (await json('__gm.tab()')) === 'list');
|
||||
|
||||
Reference in new issue
Block a user