From 1f1c6d92b1c8793f1d5f01bfe4dde28aef25dd40 Mon Sep 17 00:00:00 2001 From: Emi Matchu Date: Sun, 29 Sep 2024 14:55:30 -0700 Subject: [PATCH] Oops, fix item page's "Customize More" not animating after color change Ah whoops, I didn't notice that, when Turbo morphs the `` into what the server HTML returns, it deletes the `style` attribute we were using. In this change, I refactor for `MeasuredContainer` to be the component rather than `MeasuredContent`, so that it can also be responsible for listening for changes to its own `style` prop, and remeasuring when they happen. We're also careful to avoid infinite loops, by only doing this when the property is missing! (Otherwise, setting `--natural-width` triggers the callback again, oops!) --- app/assets/javascripts/items/show.js | 30 +++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/items/show.js b/app/assets/javascripts/items/show.js index 69589a82..aff5f5dc 100644 --- a/app/assets/javascripts/items/show.js +++ b/app/assets/javascripts/items/show.js @@ -81,23 +81,35 @@ class SpeciesFacePickerOptions extends HTMLElement { } } -class MeasuredContent extends HTMLElement { +// TODO: If it ever gets wide support, remove this in favor of the CSS rule +// `interpolate-size: allow-keywords`, to animate directly from `auto`. +// https://drafts.csswg.org/css-values-5/#valdef-interpolate-size-allow-keywords +class MeasuredContainer extends HTMLElement { + static observedAttributes = ["style"]; + connectedCallback() { setTimeout(() => this.#measure(), 0); } - #measure() { - // Find our `` parent, and set our natural width - // as `var(--natural-width)` in the context of its CSS styles. - const container = this.closest("measured-container"); - if (container == null) { - throw new Error(` must be in a `); + attributeChangedCallback() { + // When `--natural-width` gets morphed away by Turbo, measure it again! + if (this.style.getPropertyValue("--natural-width") === "") { + this.#measure(); } - container.style.setProperty("--natural-width", this.offsetWidth + "px"); + } + + #measure() { + // Find our `` child, and set our natural width as + // `var(--natural-width)` in the context of our CSS styles. + const content = this.querySelector("measured-content"); + if (content == null) { + throw new Error(` must contain a `); + } + this.style.setProperty("--natural-width", content.offsetWidth + "px"); } } customElements.define("species-color-picker", SpeciesColorPicker); customElements.define("species-face-picker", SpeciesFacePicker); customElements.define("species-face-picker-options", SpeciesFacePickerOptions); -customElements.define("measured-content", MeasuredContent); +customElements.define("measured-container", MeasuredContainer);