@synopackageland/ui 0.25.19 → 0.25.21

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.25.21 (2026-11-15)
6
+
7
+ Three style passes on a sheet's opening path no longer run in script. On Studio's ordering sheet on an Android phone (Chrome, 3 alternating rounds of 5 opens against the previous release, 31.4–31.5°C, thermal status 0), the frame that ends the slide takes 17 ms (median; was 50 ms). The time to the sheet's first frame (155–168 ms), to the start of the slide (344–384 ms either way) and the longest gap during the slide (67–84 ms) are unchanged. The priming wait is unchanged: what holds the slide is the app's own work after the first frame (about 150–200 ms), and the slide already starts in the first frame after it.
8
+
9
+ ### Dialog, Sheet, BottomSheet
10
+
11
+ - **The page's scroll lock reads the scrollbar in the next frame.** A modal overlay that locks the document (`overflow: hidden`, the scrollbar's width as `padding-right` and `--scrollbar-width`) used to read `document.documentElement.clientWidth` in the task that opened it, which made the browser compute the style and layout of the just-mounted overlay there (11–23 ms on the phone). The lock now lands at the start of the next frame, before it is drawn, where the browser computes them anyway. Closing before that frame leaves the page untouched. This is a Reka patch (`build/reka-patches.json`); the installed Reka is not modified.
12
+
13
+ ### BottomSheet
14
+
15
+ - **Touch focus after the slide no longer lengthens its last frame.** At `animationend` the page's style is out of date, so focusing the panel there computed it inside the event (33–46 ms on the phone, most of it the tapped card losing focus). The panel now takes focus in a task after the frame that ends the slide has painted, one frame later than before. A field the user focused first still keeps focus; with a mouse, or after a key press, focus moves at once as before.
16
+
17
+ ### FormItem
18
+
19
+ - **No layout read when it mounts.** The automatic stacking (`direction: 'auto'`) takes the item's first width from a ResizeObserver delivery in the next frame, instead of `getBoundingClientRect()` at mount (10–16 ms on the phone inside a sheet that has just opened). The width is still drawn in that first frame. `useElementWidth` takes the new option `observeFirst` for this; its other users still read at mount.
20
+
21
+ ### Combobox
22
+
23
+ - **A closed input shows the selected option's current label.** When the options change, for example when they arrive after mount or an option is renamed, the closed input now shows the label from the new options instead of the old label or the stored value. A search in progress is left as typed, and the label update emits no `update:modelValue`.
24
+
25
+ ## 0.25.20 (2026-11-14)
26
+
27
+ ### BottomSheet
28
+
29
+ - **The slide waits for the GPU to raster the sheet, and the scrim shows at once.** The sheet first draws in place at 1% opacity, with its slide held, so its tiles are rastered before it moves. The scrim starts fading in on the first frame instead of waiting, so a tap shows right away. The slide starts once two frames in a row arrive within 40 ms of each other (the GPU has caught up), or after 150 ms at most, counted from when the sheet's first frame starts rendering (not from that frame's timestamp, which can fall before a long click handler). Duration and easing are unchanged (250 ms in, 150 ms out, `--ui-ease-standard`). The sheet and the scrim keep the same `will-change` the whole time, so they stay on the same compositor layer and keep their tiles. A fast device waits about two frames. On Studio's ordering sheet on an Android phone (median of 3 alternating rounds against the previous build), the scrim shows in the sheet's first frame, about 200–235 ms after the tap, where it used to wait for the slide (about 245–270 ms). The longest gap during the slide is about the same (117–151 ms, was 117–134 ms). Most of the time before the first frame is the app's click handler (about 150 ms).
30
+ - **A lighter shadow:** the sheet casts the bar's short upward shadow (`--ui-shadow-bar`) instead of the dialog's 40px one. Under the scrim it looks the same, and the sheet rasters about a third faster. Desktop dialogs keep `--ui-shadow-dialog`.
31
+ - **Touch focus waits for the slide:** on touch, the panel takes focus when the opening animation ends, instead of in the opening task. Focusing there forced a style pass before the first frame (12–17 ms), and moving focus off the pressed card repainted the page under the sliding sheet. A field the user focuses first keeps focus. With a mouse, or after a key press, focus still moves at once (the first field, or the panel on touch), as before.
32
+
33
+ ### AppLayout
34
+
35
+ - **The phone nav drawer casts the card's short shadow** (`--ui-shadow-card`) instead of the dialog's 40px one. The scrim already sets it apart, and the wide blur slows its raster on a phone.
36
+
5
37
  ## 0.25.19 (2026-11-14)
6
38
 
7
39
  ### Button
@@ -3,8 +3,15 @@ import { Ref } from 'vue';
3
3
  * resize the document viewport. Zero is unknown (e.g. hidden tab or SSR).
4
4
  * `after` holds the first measurement until it is true (a containing layout
5
5
  * that has not drawn its own measured layout yet); `onMeasured` runs once the
6
- * first measurement has been drawn. */
6
+ * first measurement has been drawn.
7
+ *
8
+ * `observeFirst` takes the first width from a ResizeObserver delivery instead
9
+ * of reading it at mount. A read at mount forces the browser to compute the
10
+ * style and layout of everything changed so far in that task (a sheet that has
11
+ * just opened, say); the delivery comes in the next frame's own layout, and the
12
+ * width it commits is drawn in that same frame. */
7
13
  export declare function useElementWidth(element: Readonly<Ref<HTMLElement | null | undefined>>, options?: {
8
14
  after?: Readonly<Ref<boolean>>;
9
15
  onMeasured?: () => void;
16
+ observeFirst?: boolean;
10
17
  }): Ref<number, number>;