studio-engine 0.141.1 → 0.141.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3ccc2c2e35d236c2709dc7a7918d2a1357d81e23e4a4ed31ae1e6a8a3fee555
4
- data.tar.gz: 9af1f5d8ab55210882a7c1ad7e0ff8cc871e3938f853de749307c07ce8bfd9bd
3
+ metadata.gz: e37b982954e7699c21010d1269c9f8bb50e3f4b900b580216ab2a61907000cbb
4
+ data.tar.gz: 2288aaaee5f9f64ed85893a1ea3d5c6f2027316fc00e1da2ef1370e597037994
5
5
  SHA512:
6
- metadata.gz: 1c7fc9c56b2bd6bc48d4e1f595a2aa4f884b7c18cd3f61a9170164d1d24f19873810026a91a4ab1b8d022ac1c0e1d4965a042b4fc5194782d70d011c5604215c
7
- data.tar.gz: 8e2724c527406edbc340d96783a3f2194acc3a6008fd530f12f2f4c7c585eba56516fa76d105b1aee2cccf8c0a7c0c6477229691b09f7640052d8a6b35516ec9
6
+ metadata.gz: 9ba01f6b9d3ca61b788e4076c04e1e9699fa602214d026267cf82e0839ea4a2b89f93d66e2ec7b532475bbd32fb77481ae6d4680594ea075c6c0c189f19bcc20
7
+ data.tar.gz: f6f06cecfe7ef957aef4b61ecc586f972b264f9e13e2ca7502154b947fdcbc9a63a3d138b8c3903bace7f4200be6046ec4dcc41b89d863c70e8e438d30d80e38
data/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This pro
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.141.2 — 2026-11-09
8
+
9
+ ### Fixed
10
+
11
+ - **The link-preview card shows text typed before its controller loads.** The `link-preview-card` controller is registered lazily, so an operator could type in /admin/link_preview before it listened, and the card kept the saved title. `connect()` now paints the card from the fields as they stand (`paintAll` in `studio/link_preview_card`). No host change.
12
+ - **An in-page jump ends at the browser's scrollend, not at a quiet spell.** `studio/in_page_links` ended a smooth jump after 150 ms with no scroll event, even in a browser that fires `scrollend`. On a slow main thread (a phone, or CI at 8x CPU) a smooth scroll's frames come further apart than that, so the jump ended at its first frame: the tab highlight followed the passing sections, and a target that moved on the way (a lazy feed above it) was not aimed at again. Now only `scrollend` ends a scroll that moved, where the browser has it; the quiet spell stays for a browser without it, and the 400 ms cap still ends a scroll that never starts. Nothing for a consumer to do.
13
+
7
14
  ## 0.141.1 — 2026-11-09
8
15
 
9
16
  ### Fixed
@@ -7,8 +7,13 @@
7
7
  //
8
8
  // The repaint is studio/link_preview_card. One listener on the root takes the
9
9
  // `input` of every [data-link-preview-input] inside it.
10
+ //
11
+ // The controller is registered lazily, so its module arrives after the page has
12
+ // loaded and an operator can type before connect() listens. That input event is
13
+ // gone, so connect() also paints the card from the fields as they stand
14
+ // (e2e/site_identity.spec.js holds the module back to prove it).
10
15
  import { Controller } from "@hotwired/stimulus"
11
- import { paintCard } from "studio/link_preview_card"
16
+ import { paintCard, paintAll } from "studio/link_preview_card"
12
17
 
13
18
  export default class extends Controller {
14
19
  connect() {
@@ -17,6 +22,7 @@ export default class extends Controller {
17
22
  if (input && input.matches && input.matches("[data-link-preview-input]")) paintCard(this.element, input)
18
23
  }
19
24
  this.element.addEventListener("input", this.repaint)
25
+ paintAll(this.element)
20
26
  }
21
27
 
22
28
  disconnect() {
@@ -36,7 +36,10 @@ export const SCROLL_END_EVENT = "studio:in-page-scroll-end"
36
36
  export const STATE_KEY = "studioInPage"
37
37
  // The mark on a target that took tabindex=-1 for focus here; engine.css draws no ring on it.
38
38
  export const FOCUS_MARK = "data-in-page-focus"
39
- // No scroll for this long ends the scroll, where the browser has no scrollend event.
39
+ // No scroll for this long ends the scroll, where the browser has no scrollend event. Where it
40
+ // has one, only scrollend ends a scroll that moved: on a slow main thread (a phone, or CI at
41
+ // 8x CPU) a smooth scroll's frames come further apart than this, and a quiet spell ended the
42
+ // jump at its first frame. Then the target moved and nothing aimed again.
40
43
  export const SETTLE_MS = 150
41
44
  // A scroll the reader never sees move still ends: the cap for a scroll that never starts.
42
45
  export const START_CAP_MS = 400
@@ -188,9 +191,11 @@ export function installInPageLinks(doc) {
188
191
  // target was at the start. Content that grows on the way (a lazy frame the scroll passes,
189
192
  // the navbar's collapse) moves the target, so the scroll aims again, up to MAX_AIMS times,
190
193
  // until the reader takes over (a wheel, a touch, a key, a press). The end is the browser's
191
- // scrollend where it has one, a quiet spell where not; then the end event, once.
194
+ // scrollend where it has one, a quiet spell where not; then the end event, once. A scroll
195
+ // that never starts ends at the cap either way.
192
196
  const jump = (target, behavior) => {
193
197
  if (settling) settling()
198
+ const hasScrollend = "onscrollend" in win
194
199
  let quiet = null
195
200
  let cap = null
196
201
  let aims = 0
@@ -226,7 +231,9 @@ export function installInPageLinks(doc) {
226
231
  const onScroll = () => {
227
232
  win.clearTimeout(cap)
228
233
  reaim()
229
- wait(SETTLE_MS)
234
+ // The scroll has started: with scrollend, it alone ends it (an aim's cap is spent too).
235
+ if (hasScrollend) win.clearTimeout(quiet)
236
+ else wait(SETTLE_MS)
230
237
  }
231
238
  const stop = () => {
232
239
  reader = true
@@ -234,7 +241,7 @@ export function installInPageLinks(doc) {
234
241
  }
235
242
  settling = stop
236
243
  win.addEventListener("scroll", onScroll, { passive: true })
237
- if ("onscrollend" in win) win.addEventListener("scrollend", end)
244
+ if (hasScrollend) win.addEventListener("scrollend", end)
238
245
  for (const name of INPUTS) win.addEventListener(name, takeOver, { capture: true, passive: true })
239
246
  cap = win.setTimeout(end, START_CAP_MS)
240
247
  scrollTo(target, behavior)
@@ -32,3 +32,11 @@ export function paintCard(page, input) {
32
32
  target.textContent = text
33
33
  return text
34
34
  }
35
+
36
+ // Repaints the card from every [data-link-preview-input] on the page, as each
37
+ // field stands now. The controller calls it on connect: it is registered
38
+ // lazily, so an operator can type before it listens, and that input event is
39
+ // gone.
40
+ export function paintAll(page) {
41
+ page.querySelectorAll("[data-link-preview-input]").forEach((input) => paintCard(page, input))
42
+ }
@@ -1,3 +1,3 @@
1
1
  module Studio
2
- VERSION = "0.141.1"
2
+ VERSION = "0.141.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: studio-engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.141.1
4
+ version: 0.141.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McRitchie