Update cell rendering.

This commit is contained in:
rebornix 2021-11-15 08:17:37 -08:00
parent 8f37bcaf6e
commit 4dde912b9e
No known key found for this signature in database
GPG key ID: 0299D52A1BBA52AB

View file

@ -1,6 +1,50 @@
# Notebook Layout
The notebook editor is a virtualized list view rendered in two contexts (mainframe and webview/iframe). It's on top of the builtin list/tree view renderer but its experience is different from traditional list views like File Explorer and Settings Editor. This doc covers the architecture of the notebook editor and layout optimiziations we experimented.
The notebook editor is a virtualized list view rendered in two contexts (mainframe and webview/iframe). Since most elements' positions are absoulte and there is latency between the two frames, we have multiple optimizations to ensure smooth (we try our best) perceived user experience. The optimizations are mostly around:
# Archtecture
## Cell rendering
The rendering of cells in the notebook editor consists of following steps:
* Update reused DOM nodes in the template and cell decorations
* Set up context for the cell and toolbars
* Update cell toolbar, run toolbar and insertion toolbar between cells
* Render cell
* Register listeners for:
* Notebook layout change
* Cell layout change
* Cell state change: Folding, Collapse, Focus
## Focus Tracking
Due to the nature of virtualization (list view) and two layers architecture, the focus tracking is more complex compared to file explorer or monaco editor. When a notebook is *focused*, the `document.activeElement` can be
* Monaco editor, when users focus on a cell editor
* `textarea` when users focus the text
* Widgets
* Webview/iframe, when users focus on markdown cell or rich outputs rendered rendered in iframe
* List view container, when users focus on cell container
* Focusable element inside the notebook editor
* Builtin output (e.g., text output)
* Find Widget
* Cell statusbar
* Toolbars
The catch here is if the focus is on a monaco editor, instead of the list view container, when the cell is moved out of view, the list view removes the cell row from the DOM tree. The `document.activeElement` will fall back `document.body` when that happens. To ensure that the notebook editor doesn't blur, we need to move focus back to list view container when the focused cell is moved out of view. More importantly, focus the cell editor again when the cell is visible again (if the cell is still the *active* cell).
Copy in Notebook depends on the focus tracking
* Send `document.executeCommand('copy')` if users select text in output rendered in main frame by builtin renderer
* Request webview copy if the focus is inside the webview
* Copy cells if the focus is on notebook cell list
* Copy text if the focus is in cell editor (monaco editor)
![diagram](https://user-images.githubusercontent.com/876920/141730905-2818043e-1a84-45d3-ad27-83bd89235ca5.png)
# Optimizations
Since most elements' positions are absoulte and there is latency between the two frames, we have multiple optimizations to ensure smooth (we try our best) perceived user experience. The optimizations are mostly around:
* Ensure the elements in curent viewport are stable when other elements dimensions update
* Fewer layout messages between the main and iframe
@ -66,31 +110,3 @@ If the new output is rendered within 200ms, users won't see the UI movement.
Code cell outputs and markdown cells are rendered in the webview, which are async in nature. In order to have the cell outputs and markdown previews rendered when users scroll to them, we send rendering requests of cells in the next viewport when it's idle. Thus scrolling downwards is smoother.
However, we **don't** warmup the previous viewport as the cell height change of previous viewport might trigger the flickering of markdown cells in current viewport. Before we optimize this, do not do any warmup of cells before current viewport.
## Focus Tracking
Due to the nature of virtualization (list view) and two layers architecture, the focus tracking is more complex compared to file explorer or monaco editor. When a notebook is *focused*, the `document.activeElement` can be
* Monaco editor, when users focus on a cell editor
* `textarea` when users focus the text
* Widgets
* Webview/iframe, when users focus on markdown cell or rich outputs rendered rendered in iframe
* List view container, when users focus on cell container
* Focusable element inside the notebook editor
* Builtin output (e.g., text output)
* Find Widget
* Cell statusbar
* Toolbars
The catch here is if the focus is on a monaco editor, instead of the list view container, when the cell is moved out of view, the list view removes the cell row from the DOM tree. The `document.activeElement` will fall back `document.body` when that happens. To ensure that the notebook editor doesn't blur, we need to move focus back to list view container when the focused cell is moved out of view. More importantly, focus the cell editor again when the cell is visible again (if the cell is still the *active* cell).
Copy in Notebook depends on the focus tracking
* Send `document.executeCommand('copy')` if users select text in output rendered in main frame by builtin renderer
* Request webview copy if the focus is inside the webview
* Copy cells if the focus is on notebook cell list
* Copy text if the focus is in cell editor (monaco editor)
![diagram](https://user-images.githubusercontent.com/876920/141730905-2818043e-1a84-45d3-ad27-83bd89235ca5.png)