Skip to content

Commit

Permalink
Avoid a flash of incorrect sizing by forwarding fill potential before…
Browse files Browse the repository at this point in the history
… displaying the view (#136)
  • Loading branch information
cpsievert authored Feb 12, 2024
1 parent 780f029 commit 24e3162
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [UNRELEASED]

* Widgets no longer have a "flash" of incorrect size when first rendered. (#133)
* `@render_widget` now works properly with `Widget`s that aren't `DOMWidget`s (i.e., widgets that aren't meant to be displayed directly). As a result, you can now use `@render_widget` to gain a reference to the widget instance, and then use that reference to update the widget's value. (#133)

## [0.3.0] - 2024-01-25
Expand Down
1 change: 1 addition & 0 deletions examples/outputs/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
bokeh_dependency(),
ui.output_ui("figure", fill=True, fillable=True),
title="Hello Jupyter Widgets in Shiny for Python",
fillable=True,
)


Expand Down
26 changes: 5 additions & 21 deletions js/src/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ class IPyWidgetOutput extends Shiny.OutputBinding {
el.style.visibility = "inherit";
}

// Only forward the potential to fill if `output_widget(fillable=True)`
// _and_ the widget instance wants to fill
const fill = data.fill && el.classList.contains("html-fill-container");
if (fill) el.classList.add("forward-fill-potential");

// At this time point, we should've already handled an 'open' message, and so
// the model should be ready to use
const model = await manager.get_model(data.model_id);
Expand All @@ -102,30 +107,9 @@ class IPyWidgetOutput extends Shiny.OutputBinding {
el.removeChild(el.childNodes[0]);
}

// Only carry the potential to fill (i.e., add fill classes)
// if `output_widget(fillable=True)` _and_ the widget wants to fill
const fill = data.fill && el.classList.contains("html-fill-container");

// The ipywidgets container (.lmWidget)
const lmWidget = el.children[0] as HTMLElement;

if (fill) {
// Make lmWidget a fill carrier
// el should already be a fill carrier (done during markup generation)
lmWidget?.classList.add("html-fill-container", "html-fill-item");

// lmWidget's children is the actual widget implementation.
// Ideally this would be a single element, but some widget
// implementations (e.g., pydeck, altair) have multiple direct children.
// It seems relatively safe to make all of them fill items, but there's
// at least one case where it's problematic (pydeck)
lmWidget.childNodes.forEach((child) => {
if (!(child instanceof HTMLElement)) return;
if (child.classList.contains("deckgl-ui-elements-overlay")) return;
child.classList.add("html-fill-item");
});
}

this._maybeResize(lmWidget);
}
_maybeResize(lmWidget: HTMLElement): void {
Expand Down
Loading

0 comments on commit 24e3162

Please sign in to comment.