Skip to content

Commit ae488cd

Browse files
authored
Allow scroll_into_view to work for components rendered in the same tick (#902)
1 parent 8c09761 commit ae488cd

File tree

4 files changed

+57
-20
lines changed

4 files changed

+57
-20
lines changed

mesop/examples/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
from mesop.examples import readme_app as readme_app
3939
from mesop.examples import responsive_layout as responsive_layout
4040
from mesop.examples import scroll_into_view as scroll_into_view
41+
from mesop.examples import (
42+
scroll_into_view_deferred as scroll_into_view_deferred,
43+
)
4144
from mesop.examples import starter_kit as starter_kit
4245
from mesop.examples import sxs as sxs
4346
from mesop.examples import testing as testing
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import mesop as me
2+
3+
4+
@me.stateclass
5+
class State:
6+
show_bottom_line: bool = False
7+
8+
9+
def on_load(e: me.LoadEvent):
10+
me.scroll_into_view(key="bottom_line")
11+
state = me.state(State)
12+
state.show_bottom_line = True
13+
14+
15+
@me.page(path="/scroll_into_view_deferred", on_load=on_load)
16+
def app():
17+
me.text("Scroll into view deferred")
18+
for _ in range(100):
19+
me.text("filler line")
20+
state = me.state(State)
21+
if state.show_bottom_line:
22+
me.text("bottom line", key="bottom_line")

mesop/tests/e2e/scroll_into_view_test.ts

+8
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@ test('scroll_into_view', async ({page}) => {
1212

1313
await expect(page.getByText('bottom_line')).toBeInViewport();
1414
});
15+
16+
test('scroll_into_view - works with components rendered in same tick', async ({
17+
page,
18+
}) => {
19+
await page.setViewportSize({width: 200, height: 200});
20+
await page.goto('/scroll_into_view_deferred');
21+
await expect(page.getByText('bottom line')).toBeInViewport();
22+
});

mesop/web/src/shell/shell.ts

+24-20
Original file line numberDiff line numberDiff line change
@@ -130,27 +130,31 @@ export class Shell {
130130
} else if (command.hasScrollIntoView()) {
131131
// Scroll into view
132132
const key = command.getScrollIntoView()!.getKey();
133-
const targetElements = document.querySelectorAll(
134-
`[data-key="${key}"]`,
135-
);
136-
if (!targetElements.length) {
137-
console.error(
138-
`Could not scroll to component with key ${key} because no component found`,
133+
// Schedule scroll into view to run after the current event loop tick
134+
// so that the component has time to render.
135+
setTimeout(() => {
136+
const targetElements = document.querySelectorAll(
137+
`[data-key="${key}"]`,
139138
);
140-
return;
141-
}
142-
if (targetElements.length > 1) {
143-
console.warn(
144-
'Found multiple components',
145-
targetElements,
146-
'to potentially scroll to for key',
147-
key,
148-
'. This is probably a bug and you should use a unique key identifier.',
149-
);
150-
}
151-
targetElements[0].parentElement!.scrollIntoView({
152-
behavior: 'smooth',
153-
});
139+
if (!targetElements.length) {
140+
console.error(
141+
`Could not scroll to component with key ${key} because no component found`,
142+
);
143+
return;
144+
}
145+
if (targetElements.length > 1) {
146+
console.warn(
147+
'Found multiple components',
148+
targetElements,
149+
'to potentially scroll to for key',
150+
key,
151+
'. This is probably a bug and you should use a unique key identifier.',
152+
);
153+
}
154+
targetElements[0].parentElement!.scrollIntoView({
155+
behavior: 'smooth',
156+
});
157+
}, 0);
154158
} else if (command.hasFocusComponent()) {
155159
// Focus on component
156160
const key = command.getFocusComponent()!.getKey();

0 commit comments

Comments
 (0)