@gjsify/adwaita-web 0.35.0 → 0.37.0

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.
Files changed (146) hide show
  1. package/dist/adwaita-web.css +433 -33
  2. package/dist/adwaita-web.css.map +1 -1
  3. package/lib/types/adw-shortcut-label.spec.d.ts +2 -0
  4. package/lib/types/breakpoints.d.ts +10 -12
  5. package/lib/types/elements/adw-about-dialog.d.ts +19 -36
  6. package/lib/types/elements/adw-action-row.d.ts +9 -12
  7. package/lib/types/elements/adw-alert-dialog.d.ts +0 -12
  8. package/lib/types/elements/adw-avatar.d.ts +1 -0
  9. package/lib/types/elements/adw-bottom-sheet.d.ts +7 -12
  10. package/lib/types/elements/adw-button-content.d.ts +3 -4
  11. package/lib/types/elements/adw-button-row.d.ts +1 -1
  12. package/lib/types/elements/adw-carousel.d.ts +28 -49
  13. package/lib/types/elements/adw-checks.d.ts +2 -8
  14. package/lib/types/elements/adw-combo-row.d.ts +6 -6
  15. package/lib/types/elements/adw-data-grid.d.ts +5 -10
  16. package/lib/types/elements/adw-drop-down.d.ts +3 -11
  17. package/lib/types/elements/adw-entry-row.d.ts +20 -23
  18. package/lib/types/elements/adw-icon.d.ts +2 -4
  19. package/lib/types/elements/adw-inline-view-switcher.d.ts +18 -31
  20. package/lib/types/elements/adw-navigation-split-view.d.ts +7 -12
  21. package/lib/types/elements/adw-navigation-view.d.ts +2 -10
  22. package/lib/types/elements/adw-overlay-split-view.d.ts +28 -52
  23. package/lib/types/elements/adw-password-entry-row.d.ts +4 -5
  24. package/lib/types/elements/adw-popover.d.ts +2 -7
  25. package/lib/types/elements/adw-preferences-dialog.d.ts +21 -34
  26. package/lib/types/elements/adw-preferences-group.d.ts +12 -14
  27. package/lib/types/elements/adw-progress-bar.d.ts +3 -4
  28. package/lib/types/elements/adw-shortcut-label.d.ts +20 -0
  29. package/lib/types/elements/adw-sidebar.d.ts +5 -10
  30. package/lib/types/elements/adw-spinner.d.ts +3 -5
  31. package/lib/types/elements/adw-split-button.d.ts +6 -16
  32. package/lib/types/elements/adw-switch-row.d.ts +3 -3
  33. package/lib/types/elements/adw-tab-view.d.ts +16 -26
  34. package/lib/types/elements/adw-toast-overlay.d.ts +8 -13
  35. package/lib/types/elements/adw-view-stack.d.ts +7 -17
  36. package/lib/types/elements/adw-view-switcher-bar.d.ts +4 -8
  37. package/lib/types/elements/adw-view-switcher.d.ts +18 -38
  38. package/lib/types/elements/adw-wrap-box.d.ts +7 -17
  39. package/lib/types/elements/view-switcher-dom.d.ts +10 -13
  40. package/lib/types/index.d.ts +1 -0
  41. package/lib/types/source-view/hex.d.ts +7 -13
  42. package/lib/types/style-classes.spec.d.ts +11 -0
  43. package/lib/types/styles.generated.d.ts +1 -1
  44. package/package.json +6 -6
  45. package/scss/_about_dialog.scss +3 -2
  46. package/scss/_action_row.scss +33 -0
  47. package/scss/_avatar.scss +12 -0
  48. package/scss/_button.scss +44 -22
  49. package/scss/_card.scss +11 -8
  50. package/scss/_checks.scss +2 -4
  51. package/scss/_dialog.scss +3 -2
  52. package/scss/_headerbar.scss +23 -0
  53. package/scss/_popover.scss +8 -4
  54. package/scss/_preferences.scss +7 -7
  55. package/scss/_progress_bar.scss +9 -6
  56. package/scss/_reset.scss +1 -1
  57. package/scss/_shortcut_label.scss +80 -0
  58. package/scss/_sidebar.scss +57 -0
  59. package/scss/_status_page.scss +20 -0
  60. package/scss/_style_classes.scss +407 -0
  61. package/scss/_switch.scss +4 -3
  62. package/scss/_variables.scss +25 -0
  63. package/scss/adwaita-skin.scss +12 -0
  64. package/src/adw-about-dialog.spec.ts +34 -49
  65. package/src/adw-action-rows.spec.ts +25 -33
  66. package/src/adw-avatar.spec.ts +51 -20
  67. package/src/adw-banner.spec.ts +5 -8
  68. package/src/adw-button-content.spec.ts +9 -12
  69. package/src/adw-button-row.spec.ts +2 -4
  70. package/src/adw-carousel.spec.ts +40 -53
  71. package/src/adw-checks.spec.ts +36 -47
  72. package/src/adw-drop-down.spec.ts +25 -32
  73. package/src/adw-header-bar.spec.ts +5 -7
  74. package/src/adw-icon.spec.ts +23 -32
  75. package/src/adw-progress-bar.spec.ts +10 -12
  76. package/src/adw-row-state.spec.ts +9 -10
  77. package/src/adw-shortcut-label.spec.ts +112 -0
  78. package/src/adw-sidebar.spec.ts +17 -24
  79. package/src/adw-switch.spec.ts +11 -17
  80. package/src/adw-tab-view.spec.ts +7 -10
  81. package/src/adw-toast-overlay.spec.ts +7 -11
  82. package/src/adw-view-switcher-bar.spec.ts +10 -14
  83. package/src/adw-wrap-box.spec.ts +25 -36
  84. package/src/bottom-sheet.spec.ts +30 -36
  85. package/src/breakpoints.ts +15 -18
  86. package/src/chrome.spec.ts +13 -21
  87. package/src/elements/adw-about-dialog.ts +71 -114
  88. package/src/elements/adw-action-row.ts +22 -37
  89. package/src/elements/adw-alert-dialog.ts +25 -50
  90. package/src/elements/adw-avatar.ts +40 -15
  91. package/src/elements/adw-banner.ts +14 -18
  92. package/src/elements/adw-bottom-sheet.ts +31 -52
  93. package/src/elements/adw-button-content.ts +30 -37
  94. package/src/elements/adw-button-row.ts +14 -24
  95. package/src/elements/adw-carousel.ts +87 -148
  96. package/src/elements/adw-checks.ts +43 -56
  97. package/src/elements/adw-clamp.ts +8 -9
  98. package/src/elements/adw-combo-row.ts +17 -25
  99. package/src/elements/adw-data-grid.ts +26 -38
  100. package/src/elements/adw-dialog.ts +25 -56
  101. package/src/elements/adw-drop-down.ts +31 -51
  102. package/src/elements/adw-entry-row.ts +39 -46
  103. package/src/elements/adw-expander-row.ts +30 -53
  104. package/src/elements/adw-icon.ts +30 -53
  105. package/src/elements/adw-inline-view-switcher.ts +38 -67
  106. package/src/elements/adw-menu-button.ts +28 -58
  107. package/src/elements/adw-navigation-split-view.ts +35 -47
  108. package/src/elements/adw-navigation-view.ts +12 -28
  109. package/src/elements/adw-overlay-split-view.ts +100 -175
  110. package/src/elements/adw-password-entry-row.ts +18 -28
  111. package/src/elements/adw-popover.ts +28 -44
  112. package/src/elements/adw-preferences-dialog.ts +41 -66
  113. package/src/elements/adw-preferences-group.ts +33 -46
  114. package/src/elements/adw-progress-bar.ts +27 -47
  115. package/src/elements/adw-shortcut-label.ts +138 -0
  116. package/src/elements/adw-sidebar.ts +31 -39
  117. package/src/elements/adw-spin-row.ts +7 -14
  118. package/src/elements/adw-spinner.ts +31 -43
  119. package/src/elements/adw-split-button.ts +45 -75
  120. package/src/elements/adw-switch-row.ts +29 -46
  121. package/src/elements/adw-switch.ts +28 -47
  122. package/src/elements/adw-tab-view.ts +62 -103
  123. package/src/elements/adw-toast-overlay.ts +28 -35
  124. package/src/elements/adw-toggle-group.ts +9 -16
  125. package/src/elements/adw-view-stack.ts +32 -51
  126. package/src/elements/adw-view-switcher-bar.ts +26 -50
  127. package/src/elements/adw-view-switcher.ts +60 -110
  128. package/src/elements/adw-window-title.ts +4 -4
  129. package/src/elements/adw-wrap-box.ts +33 -59
  130. package/src/elements/view-switcher-dom.ts +15 -22
  131. package/src/entry-rows.spec.ts +18 -24
  132. package/src/index.ts +13 -15
  133. package/src/navigation-view.spec.ts +7 -10
  134. package/src/preferences-search.ts +11 -15
  135. package/src/preferences.spec.ts +13 -15
  136. package/src/source-view/adw-source-view.ts +6 -19
  137. package/src/source-view/hex.ts +7 -13
  138. package/src/split-button.spec.ts +32 -44
  139. package/src/split-views.spec.ts +83 -149
  140. package/src/style-classes.spec.ts +181 -0
  141. package/src/style-isolation.spec.ts +3 -6
  142. package/src/styles.generated.ts +1 -1
  143. package/src/tab-view.spec.ts +26 -35
  144. package/src/test.browser.mts +4 -0
  145. package/src/view-stack.spec.ts +23 -34
  146. package/src/view-switcher.spec.ts +56 -84
@@ -1,53 +1,24 @@
1
1
  // <adw-carousel> — a swipeable pager (the web counterpart of Adw.Carousel).
2
- // Pages are declared as direct children; the carousel lays them out in a
3
- // scroll-snap strip, tracks the fractional scroll position, and exposes the
4
- // AdwCarousel properties and signals.
2
+ // Pages are declared as direct children.
5
3
  //
6
- // The BEHAVIOUR is headless and lives in `@gjsify/adwaita-core` (ADR 0004) as
7
- // {@link CarouselState}, shared with the NativeScript twin and pinned by the
8
- // conformance vectors in `@gjsify/adwaita-core/conformance`: snap points, the
9
- // range and its clamp, which page a position settles on, the wheel axis rules
10
- // and their 150 ms lockout, the keynav step, and the insert/reorder/remove
11
- // ordering with its position compensation. This element is the DOM half only —
12
- // it turns children into a scroll-snap strip, converts scroll offsets to and
13
- // from positions, and re-emits changes as DOM events.
4
+ // The BEHAVIOUR is headless, in `@gjsify/adwaita-core`'s {@link CarouselState}
5
+ // (ADR 0004), shared with the NativeScript twin and pinned by
6
+ // `@gjsify/adwaita-core/conformance`: snap points and range clamp, which page a
7
+ // position settles on (C's half-DOWN tie-break), the wheel axis rules and their
8
+ // 150 ms lockout (`scroll_cb`), the keynav step, and insert/reorder/remove with its
9
+ // position compensation. This element is the DOM half only — scroll-snap strip,
10
+ // offset↔position, DOM events.
14
11
  //
15
- // What the lift fixed here, all of it C-derived:
16
- // - `allow-scroll-wheel` defaults to TRUE (adw-carousel.c:1103-1106, :1201).
17
- // It was read as a bare attribute presence, so a plain <adw-carousel>
18
- // ignored the wheel entirely while the header comment claimed the opposite,
19
- // and every doc example had to opt in.
20
- // - the wheel now follows `scroll_cb` (:537-574): a touchpad propagates, a
21
- // mouse wheel pages a horizontal carousel, a horizontal delta is the
22
- // fallback the old `|dy| <= |dx|` early-return dropped, exactly one page per
23
- // notch behind a 150 ms lockout instead of a non-decaying accumulator (which
24
- // cancelled +30 then −30 out), and the event is consumed ONLY when it paged.
25
- // - `page-changed` fires on every settle, including back onto the same page,
26
- // and can report -1 (:363-376, :1150-1151); it used to be gated on an index
27
- // change, which made -1 unreachable.
28
- // - a fractional position resolves to a page with C's half-DOWN tie-break
29
- // (:198-201), where `Math.round` picked the later page at every .5.
30
- // - `allow-long-swipes` was dead code (`step * 1` vs `step`). It now maps onto
31
- // `scroll-snap-stop`, which is the same rule in CSS: one flick, one page.
32
- // - `<adw-carousel position="2">` used to be dropped, because attribute
33
- // changes are delivered before `connectedCallback`; and the attribute path
34
- // parsed with `parseInt` while the property path rounded. Both now parse a
35
- // float and resolve it through the same page lookup.
36
- // - the page list is no longer frozen at `connectedCallback`: `insertPage` /
37
- // `removePage` / `reorderPage` mirror the C methods (:1370-1532).
12
+ // The three attribute defaults HTML cannot spell: `allow-scroll-wheel` and
13
+ // `interactive` default TRUE, so `="false"` is the off switch; `allow-long-swipes`
14
+ // is an ordinary presence attribute. `position` is the INITIAL page only —
15
+ // write-only, with the live value on the `position` property and `notify::position`.
38
16
  //
39
- // adw-carousel
40
- // Attributes: allow-scroll-wheel (default TRUE, set "false" to disable),
41
- // allow-long-swipes (default false), interactive (default TRUE),
42
- // spacing (px between pages, default 0), position (INITIAL/declarative page
43
- // to show — write-only, the live position is the `position` property and the
44
- // `notify::position` event).
45
- // Events: `notify::position` (fractional scroll position changed),
46
- // `notify::n-pages` (page count changed), `page-changed`
47
- // (`detail = { index }`, -1 when empty).
48
- // adw-carousel-indicator-dots / adw-carousel-indicator-lines
49
- // Properties: carousel (the bound AdwCarousel element), or a `for` attribute
50
- // with the carousel element's id.
17
+ // `page-changed` (`detail = { index }`) fires on every settle, including back
18
+ // onto the same page, and reports -1 when empty.
19
+ //
20
+ // The indicators bind through their `carousel` property or a `for` attribute
21
+ // naming the carousel's id.
51
22
  //
52
23
  // Reference: refs/libadwaita/src/adw-carousel.c (AdwCarousel behaviour)
53
24
  // Reference: refs/libadwaita/src/adw-carousel-indicator-dots.c
@@ -74,15 +45,13 @@ interface CarouselHost extends HTMLElement {
74
45
  const WHEEL_NOTCH_PIXELS = 40;
75
46
 
76
47
  /**
77
- * Which `GdkInputSource` a `WheelEvent` most likely came from.
78
- *
79
- * The web platform exposes no device class, so this is a HEURISTIC where GDK has
80
- * a fact (`gdk_device_get_source`, adw-carousel.c:535-536) — but the distinction
81
- * is load-bearing: libadwaita ignores touchpad scrolling because the touchpad's
82
- * own kinetic scroll already drives the swipe, which here is the track's native
83
- * scroll-snap. Line- and page-mode deltas only ever come from a wheel; a
84
- * touchpad reports small or fractional pixel deltas, and is the only thing that
85
- * produces a horizontal component alongside a vertical one.
48
+ * Which `GdkInputSource` a `WheelEvent` most likely came from. The web platform
49
+ * exposes no device class, so this is a HEURISTIC where GDK has a fact
50
+ * (`gdk_device_get_source`), and the distinction is load-bearing: libadwaita ignores
51
+ * touchpad scrolling because the touchpad's own kinetic scroll already drives the
52
+ * swipe — here, the track's native scroll-snap. Line- and page-mode deltas only ever
53
+ * come from a wheel; a touchpad reports small or fractional pixel deltas and is the
54
+ * only source of a horizontal component alongside a vertical one.
86
55
  */
87
56
  function wheelSource(event: WheelEvent): CarouselScrollSource {
88
57
  if (event.deltaMode !== 0) return 'mouse';
@@ -123,15 +92,14 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
123
92
 
124
93
  constructor() {
125
94
  super();
126
- // Subscribing touches no attributes and no children, so it is legal in a
127
- // custom element constructor — unlike anything DOM-shaped.
95
+ // Legal in a custom-element constructor: subscribing touches no attributes
96
+ // and no children, unlike anything DOM-shaped.
128
97
  this._state.subscribe((change) => this._onStateChange(change));
129
98
  this._state.onPageChanged((index) => {
130
99
  this.dispatchEvent(new CustomEvent('page-changed', { bubbles: true, detail: { index } }));
131
100
  });
132
101
  }
133
102
 
134
- /** Number of pages in the carousel. */
135
103
  get nPages(): number {
136
104
  return this._state.nPages;
137
105
  }
@@ -142,18 +110,15 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
142
110
  }
143
111
 
144
112
  /**
145
- * Scroll to the page this position settles on.
146
- *
147
- * `AdwCarousel:position` is READ-ONLY in C (adw-carousel.c:1036-1041) — the
148
- * setter is a port convenience, and it resolves the value with the same
149
- * `get_page_at_position` rule the carousel uses everywhere else, so setting
150
- * 0.5 lands on page 0 exactly as scrolling there would.
113
+ * Scroll to the page this position settles on. MODIFICATION: `AdwCarousel:position`
114
+ * is READ-ONLY in C; this setter is a port convenience that resolves through the
115
+ * same `get_page_at_position` rule, so 0.5 lands on page 0 exactly as scrolling
116
+ * there would.
151
117
  */
152
118
  set position(value: number) {
153
119
  this._scrollToPosition(value);
154
120
  }
155
121
 
156
- /** The page the current position settles on, `-1` when the carousel is empty. */
157
122
  get currentPage(): number {
158
123
  return this._state.pageAt(this._state.position);
159
124
  }
@@ -167,7 +132,6 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
167
132
  this.setAttribute('allow-scroll-wheel', value ? 'true' : 'false');
168
133
  }
169
134
 
170
- /** Whether a single flick may cross more than one page. */
171
135
  get allowLongSwipes(): boolean {
172
136
  return this._state.allowLongSwipes;
173
137
  }
@@ -200,15 +164,13 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
200
164
 
201
165
  this._trackEl = document.createElement('div');
202
166
  this._trackEl.className = 'adw-carousel-track';
203
- // The scroll animation is CSS, not a hard-coded `behavior: 'smooth'`, so
204
- // it stays overridable: a consumer honouring prefers-reduced-motion, or a
205
- // test that needs the scroll to land now, sets `scroll-behavior: auto` on
206
- // the track and every scroll becomes instant.
167
+ // CSS rather than a hard-coded `behavior: 'smooth'`, so it stays
168
+ // overridable: `scroll-behavior: auto` on the track makes every scroll
169
+ // instant, for prefers-reduced-motion or for a test that needs it to land now.
207
170
  this._trackEl.style.setProperty('scroll-behavior', 'smooth');
208
171
 
209
- // Read the declared properties BEFORE adopting children: `spacing` is
210
- // part of the page pitch, so a page added first would be measured
211
- // against the wrong distance.
172
+ // Declared properties BEFORE children: `spacing` is part of the page pitch,
173
+ // so a page added first would be measured against the wrong distance.
212
174
  this._applyAttribute('allow-scroll-wheel', this.getAttribute('allow-scroll-wheel'));
213
175
  this._applyAttribute('allow-long-swipes', this.getAttribute('allow-long-swipes'));
214
176
  this._applyAttribute('interactive', this.getAttribute('interactive'));
@@ -223,10 +185,9 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
223
185
  this._trackEl.addEventListener('scroll', this._onScroll, { passive: true });
224
186
  this._trackEl.addEventListener('wheel', this._onWheel, { passive: false });
225
187
 
226
- // A declared `position` is applied last, once the pages it names exist.
227
- // Custom-element upgrade delivers attributes BEFORE connectedCallback, so
228
- // reading it here is the only way `<adw-carousel position="2">` works at
229
- // all — it used to be dropped on the floor.
188
+ // Applied last, once the pages it names exist. Custom-element upgrade
189
+ // delivers attributes BEFORE `connectedCallback`, so reading it here is the
190
+ // only way `<adw-carousel position="2">` works at all.
230
191
  this._applyAttribute('position', this.getAttribute('position'));
231
192
  }
232
193
 
@@ -236,12 +197,11 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
236
197
  }
237
198
 
238
199
  disconnectedCallback() {
239
- // A pending declared position watches the track for its first layout;
240
- // a carousel removed before that happens must not keep an observer alive.
200
+ // A pending declared position watches the track for its first layout; a
201
+ // carousel removed before that must not keep the observer alive.
241
202
  this._cancelPendingPosition();
242
203
  }
243
204
 
244
- /** One attribute → one state property. Shared by the initial read and later changes. */
245
205
  private _applyAttribute(name: string, value: string | null): void {
246
206
  switch (name) {
247
207
  case 'allow-scroll-wheel':
@@ -263,22 +223,18 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
263
223
  return;
264
224
  }
265
225
  case 'position':
266
- // One parse for both paths. The attribute used to go through
267
- // parseInt while the property rounded, so "1.7" meant page 1
268
- // declaratively and page 2 imperatively.
226
+ // One parse for both paths, so `1.7` resolves the same declaratively
227
+ // and imperatively.
269
228
  if (value !== null) this._positionWhenMeasurable(Number.parseFloat(value));
270
229
  }
271
230
  }
272
231
 
273
232
  /**
274
- * Scroll to `value`, waiting for the first layout when the track has no
275
- * width yet.
276
- *
277
- * `connectedCallback` runs DURING insertion, so the track is still 0px wide
278
- * and a scroll offset has nowhere to land — a declared
279
- * `<adw-carousel position="2">` silently stayed on page 0. Deferring to the
280
- * first non-zero measurement is the only point at which the offset means
281
- * anything; a later assignment simply replaces the pending one.
233
+ * Scroll to `value`, waiting for the first layout when the track has no width yet:
234
+ * `connectedCallback` runs DURING insertion, so the track is still 0px wide and a
235
+ * scroll offset has nowhere to land. The first non-zero measurement is the earliest
236
+ * point at which the offset means anything; a later assignment replaces the pending
237
+ * one.
282
238
  */
283
239
  private _positionWhenMeasurable(value: number): void {
284
240
  if (!Number.isFinite(value)) return;
@@ -299,14 +255,11 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
299
255
  }
300
256
 
301
257
  /**
302
- * Jump to `value` without the reveal animation.
303
- *
304
- * A DECLARED position is where the carousel STARTS, not somewhere it travels
305
- * to — `<adw-carousel position="2">` should render already showing page 2.
306
- * Left smooth, the track is still at offset 0 while the animation runs, and
307
- * the `scroll` event that fires from there recomputes the position back to
308
- * page 0. So the one assignment is made instant and the caller's
309
- * `scroll-behavior` is put back.
258
+ * Jump to `value` without the reveal animation: a DECLARED position is where the
259
+ * carousel STARTS, not somewhere it travels to. Left smooth, the track is still at
260
+ * offset 0 while the animation runs and the `scroll` event fired from there
261
+ * recomputes the position back to page 0 — so this one assignment is made instant
262
+ * and the caller's `scroll-behavior` restored.
310
263
  */
311
264
  private _scrollInstantly(value: number): void {
312
265
  const previous = this._trackEl.style.getPropertyValue('scroll-behavior');
@@ -319,14 +272,12 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
319
272
  }
320
273
  }
321
274
 
322
- /** Drop a pending declared position and stop watching for a layout. */
323
275
  private _cancelPendingPosition(): void {
324
276
  this._pendingLayout?.disconnect();
325
277
  this._pendingLayout = undefined;
326
278
  this._pendingPosition = null;
327
279
  }
328
280
 
329
- /** Resolve a fractional position to a page and scroll there; a no-op when there is none. */
330
281
  private _scrollToPosition(value: number): void {
331
282
  if (!Number.isFinite(value)) return;
332
283
  const page = this._state.pageAt(value);
@@ -334,7 +285,7 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
334
285
  }
335
286
 
336
287
  /**
337
- * Insert `page` at `position` — `adw_carousel_insert` (adw-carousel.c:1370-1407).
288
+ * Insert `page` at `position` — `adw_carousel_insert`.
338
289
  * `-1` or a position past the end appends. Returns whether it was added.
339
290
  */
340
291
  insertPage(page: HTMLElement, position = -1): boolean {
@@ -345,29 +296,29 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
345
296
  return this._insert(page, position);
346
297
  }
347
298
 
348
- /** `adw_carousel_append` (adw-carousel.c:1348-1357). */
299
+ /** `adw_carousel_append`. */
349
300
  appendPage(page: HTMLElement): boolean {
350
301
  return this.insertPage(page, -1);
351
302
  }
352
303
 
353
- /** `adw_carousel_prepend` (adw-carousel.c:1330-1339). */
304
+ /** `adw_carousel_prepend`. */
354
305
  prependPage(page: HTMLElement): boolean {
355
306
  return this.insertPage(page, 0);
356
307
  }
357
308
 
358
- /** Remove `page` — `adw_carousel_remove` (adw-carousel.c:1508-1532). */
309
+ /** Remove `page` — `adw_carousel_remove`. */
359
310
  removePage(page: HTMLElement): boolean {
360
311
  const id = this._idOf(page);
361
312
  if (id === null) return false;
362
313
  if (!this._state.removePage(id)) return false;
363
314
  // reveal-duration is 0 by default and this port has no reveal ramp, so
364
- // the shrink completes at once — `adw_animation_skip` (:331).
315
+ // the shrink completes at once — `adw_animation_skip`.
365
316
  this._state.skipReveal(id);
366
317
  this._syncTrack();
367
318
  return true;
368
319
  }
369
320
 
370
- /** Move `page` — `adw_carousel_reorder` (adw-carousel.c:1419-1499). */
321
+ /** Move `page` — `adw_carousel_reorder`. */
371
322
  reorderPage(page: HTMLElement, position: number): boolean {
372
323
  const id = this._idOf(page);
373
324
  if (id === null) return false;
@@ -379,13 +330,13 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
379
330
  /**
380
331
  * Scroll to the page at `index`. Out-of-range, fractional and NaN indices are
381
332
  * refused rather than clamped, matching `adw_carousel_get_nth_page`'s
382
- * precondition (adw-carousel.c:1616).
333
+ * precondition.
383
334
  */
384
335
  scrollToPage(index: number): void {
385
336
  this._state.scrollTo(index);
386
337
  }
387
338
 
388
- /** One keynav step — `navigate_to_direction` (adw-carousel.c:475-508). */
339
+ /** One keynav step — `navigate_to_direction`. */
389
340
  navigate(direction: 'back' | 'forward'): boolean {
390
341
  return this._state.navigate(direction);
391
342
  }
@@ -406,13 +357,11 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
406
357
  return true;
407
358
  }
408
359
 
409
- /** The state's id for a page element, or `null` when it is not one of ours. */
410
360
  private _idOf(page: HTMLElement): string | null {
411
361
  for (const [id, slot] of this._slots) if (slot.contains(page)) return id;
412
362
  return null;
413
363
  }
414
364
 
415
- /** Make the DOM order match the model order, and drop slots whose page is gone. */
416
365
  private _syncTrack(): void {
417
366
  const ids = this._state.ids;
418
367
  const live = new Set(ids);
@@ -433,14 +382,11 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
433
382
  }
434
383
 
435
384
  /**
436
- * Put the scroll offset back where the model says it is, instantly.
437
- *
438
- * A page revealed at or before the current one moves the position with it
439
- * (`shift_position`, adw-carousel.c:241-258) precisely so the page on screen
440
- * does not slide sideways — but a scroll container knows nothing about that
441
- * and would keep its old offset, showing the newly-inserted page instead. GTK
442
- * gets this for free because the same allocation that adds the child also
443
- * lays it out; here it takes one write.
385
+ * Put the scroll offset back where the model says it is, instantly. A page revealed
386
+ * at or before the current one moves the position with it (`shift_position`)
387
+ * precisely so the page on screen does not slide sideways — but a scroll container
388
+ * keeps its old offset and would show the newly-inserted page instead. GTK gets this
389
+ * from the allocation that adds the child; here it takes one write.
444
390
  */
445
391
  private _applyScrollFromModel(): void {
446
392
  const distance = this._distance();
@@ -451,29 +397,28 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
451
397
  /**
452
398
  * `allow-long-swipes` in CSS: `scroll-snap-stop: always` forces the scroll to
453
399
  * stop at every page, which is exactly what the property being FALSE means —
454
- * "each swipe can only move to the adjacent pages" (adw-carousel.c:1111-1113).
400
+ * "each swipe can only move to the adjacent pages".
455
401
  */
456
402
  private _applySnapStop(): void {
457
403
  const stop = this._state.allowLongSwipes ? 'normal' : 'always';
458
404
  for (const slot of this._slots.values()) slot.style.setProperty('scroll-snap-stop', stop);
459
405
  }
460
406
 
461
- /** The px pitch between two page origins — `self->distance` (adw-carousel.c:767). */
407
+ /** The px pitch between two page origins — `self->distance`. */
462
408
  private _distance(): number {
463
409
  const first = this._trackEl?.firstElementChild as HTMLElement | null;
464
410
  if (!first) return 0;
465
411
  return this._state.pageDistance(first.getBoundingClientRect().width);
466
412
  }
467
413
 
468
- /** Run the scroll the state asked for, in the track's own scroll coordinates. */
469
414
  private _performScroll(request: CarouselScrollRequest): void {
470
415
  if (!this._trackEl) return;
471
416
  const distance = this._distance();
472
417
  if (!(distance > 0)) return;
473
418
  this._pendingInteractive = request.interactive;
474
- // `offset = distance * position` (adw-carousel.c:797-801). The old code
475
- // used `slot.offsetLeft`, which is measured from the nearest POSITIONED
476
- // ancestor and only coincides with the scroll offset by accident.
419
+ // `offset = distance * position`, NOT `slot.offsetLeft` — that is measured from
420
+ // the nearest POSITIONED ancestor and coincides with the scroll offset only by
421
+ // accident.
477
422
  this._trackEl.scrollTo({ left: request.index * distance });
478
423
  }
479
424
 
@@ -491,9 +436,8 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
491
436
  deltaY: event.deltaY,
492
437
  source: wheelSource(event),
493
438
  });
494
- // GDK_EVENT_STOP only when it actually paged (adw-carousel.c:561-562 vs
495
- // :576). The old code preventDefault()ed before its threshold test, so it
496
- // swallowed sub-threshold scrolls without doing anything with them.
439
+ // GDK_EVENT_STOP only when it actually paged — a sub-threshold scroll must
440
+ // propagate, not be swallowed.
497
441
  if (step !== 0) event.preventDefault();
498
442
  };
499
443
 
@@ -502,15 +446,14 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
502
446
  if (!(distance > 0)) return;
503
447
 
504
448
  const next = this._trackEl.scrollLeft / distance;
505
- // A scroll event that does not MOVE the position carries no news: it is
506
- // the echo of the offset `_applyScrollFromModel` just wrote, and reading
507
- // it back as an arrival would announce a `page-changed` for an insert
508
- // that deliberately kept the same page on screen. The notification still
509
- // goes out — C's notify at :281 is unconditional.
449
+ // A scroll event that does not MOVE the position is the echo of the offset
450
+ // `_applyScrollFromModel` just wrote; reading it back as an arrival would
451
+ // announce a `page-changed` for an insert that deliberately kept the same page
452
+ // on screen. `notify::position` still goes out — C's is unconditional too.
510
453
  if (!this._state.setPosition(next, this._pendingInteractive ?? true)) return;
511
454
  // `scroll_animation_done_cb` has an animation to tell it the scroll
512
455
  // finished; scroll-snap has only the offset, so the core stands ARRIVAL
513
- // at a snap point in for it (adw-carousel.c:363-376).
456
+ // at a snap point in for it.
514
457
  if (this._state.settleIfArrived()) this._pendingInteractive = null;
515
458
  }
516
459
 
@@ -532,7 +475,6 @@ export class AdwCarousel extends HTMLElement implements CarouselHost {
532
475
  }
533
476
  }
534
477
 
535
- /** Shared base for the dot / line indicator elements. */
536
478
  abstract class AdwCarouselIndicator extends HTMLElement {
537
479
  protected _carousel: CarouselHost | null = null;
538
480
  protected _initialized = false;
@@ -635,21 +577,18 @@ export class AdwCarouselIndicatorLines extends AdwCarouselIndicator {
635
577
  }
636
578
 
637
579
  /**
638
- * Shared rebuild for both indicator kinds: one child per page, the CURRENT page
639
- * carries `.active`, and clicking scrolls the carousel. The dot/line look (size,
640
- * growth, opacity ramp) is in SCSS, driven by a per-marker
641
- * `--adw-carousel-progress`.
580
+ * Shared rebuild for both indicator kinds: one child per page, the CURRENT page carries
581
+ * `.active`, and clicking scrolls the carousel. The dot/line look is in SCSS, driven by
582
+ * a per-marker `--adw-carousel-progress`.
642
583
  *
643
- * `current` comes from the carousel's own `get_page_at_position` rather than
644
- * from the progress ramp: the old `progress > 0.5` test left NO dot marked at an
645
- * exact half-way position — with two pages at position 0.5 both dots scored
646
- * exactly 0.5 and every one of them reported `aria-current="false"`.
584
+ * `current` comes from the carousel's `get_page_at_position`, not from the progress
585
+ * ramp: a `progress > 0.5` test marks NO dot at an exact half-way position, where both
586
+ * neighbours score exactly 0.5.
647
587
  *
648
- * The ramp itself is still the `1 − |position − i|` approximation, which is
649
- * exact only while every page is fully revealed. libadwaita's real per-dot
650
- * progress (`snapshot_dots`, adw-carousel-indicator-dots.c:114-134) also scales
651
- * radius and opacity by that page's size, which needs a reveal ramp this port
652
- * does not have.
588
+ * MODIFICATION: the ramp is the `1 − |position − i|` approximation, exact only while
589
+ * every page is fully revealed. libadwaita's real per-dot progress (`snapshot_dots`)
590
+ * also scales radius and opacity by that page's size, which needs a reveal ramp this
591
+ * port does not have.
653
592
  */
654
593
  function renderIndicator(
655
594
  host: HTMLElement,