@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.
- package/dist/adwaita-web.css +433 -33
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/adw-shortcut-label.spec.d.ts +2 -0
- package/lib/types/breakpoints.d.ts +10 -12
- package/lib/types/elements/adw-about-dialog.d.ts +19 -36
- package/lib/types/elements/adw-action-row.d.ts +9 -12
- package/lib/types/elements/adw-alert-dialog.d.ts +0 -12
- package/lib/types/elements/adw-avatar.d.ts +1 -0
- package/lib/types/elements/adw-bottom-sheet.d.ts +7 -12
- package/lib/types/elements/adw-button-content.d.ts +3 -4
- package/lib/types/elements/adw-button-row.d.ts +1 -1
- package/lib/types/elements/adw-carousel.d.ts +28 -49
- package/lib/types/elements/adw-checks.d.ts +2 -8
- package/lib/types/elements/adw-combo-row.d.ts +6 -6
- package/lib/types/elements/adw-data-grid.d.ts +5 -10
- package/lib/types/elements/adw-drop-down.d.ts +3 -11
- package/lib/types/elements/adw-entry-row.d.ts +20 -23
- package/lib/types/elements/adw-icon.d.ts +2 -4
- package/lib/types/elements/adw-inline-view-switcher.d.ts +18 -31
- package/lib/types/elements/adw-navigation-split-view.d.ts +7 -12
- package/lib/types/elements/adw-navigation-view.d.ts +2 -10
- package/lib/types/elements/adw-overlay-split-view.d.ts +28 -52
- package/lib/types/elements/adw-password-entry-row.d.ts +4 -5
- package/lib/types/elements/adw-popover.d.ts +2 -7
- package/lib/types/elements/adw-preferences-dialog.d.ts +21 -34
- package/lib/types/elements/adw-preferences-group.d.ts +12 -14
- package/lib/types/elements/adw-progress-bar.d.ts +3 -4
- package/lib/types/elements/adw-shortcut-label.d.ts +20 -0
- package/lib/types/elements/adw-sidebar.d.ts +5 -10
- package/lib/types/elements/adw-spinner.d.ts +3 -5
- package/lib/types/elements/adw-split-button.d.ts +6 -16
- package/lib/types/elements/adw-switch-row.d.ts +3 -3
- package/lib/types/elements/adw-tab-view.d.ts +16 -26
- package/lib/types/elements/adw-toast-overlay.d.ts +8 -13
- package/lib/types/elements/adw-view-stack.d.ts +7 -17
- package/lib/types/elements/adw-view-switcher-bar.d.ts +4 -8
- package/lib/types/elements/adw-view-switcher.d.ts +18 -38
- package/lib/types/elements/adw-wrap-box.d.ts +7 -17
- package/lib/types/elements/view-switcher-dom.d.ts +10 -13
- package/lib/types/index.d.ts +1 -0
- package/lib/types/source-view/hex.d.ts +7 -13
- package/lib/types/style-classes.spec.d.ts +11 -0
- package/lib/types/styles.generated.d.ts +1 -1
- package/package.json +6 -6
- package/scss/_about_dialog.scss +3 -2
- package/scss/_action_row.scss +33 -0
- package/scss/_avatar.scss +12 -0
- package/scss/_button.scss +44 -22
- package/scss/_card.scss +11 -8
- package/scss/_checks.scss +2 -4
- package/scss/_dialog.scss +3 -2
- package/scss/_headerbar.scss +23 -0
- package/scss/_popover.scss +8 -4
- package/scss/_preferences.scss +7 -7
- package/scss/_progress_bar.scss +9 -6
- package/scss/_reset.scss +1 -1
- package/scss/_shortcut_label.scss +80 -0
- package/scss/_sidebar.scss +57 -0
- package/scss/_status_page.scss +20 -0
- package/scss/_style_classes.scss +407 -0
- package/scss/_switch.scss +4 -3
- package/scss/_variables.scss +25 -0
- package/scss/adwaita-skin.scss +12 -0
- package/src/adw-about-dialog.spec.ts +34 -49
- package/src/adw-action-rows.spec.ts +25 -33
- package/src/adw-avatar.spec.ts +51 -20
- package/src/adw-banner.spec.ts +5 -8
- package/src/adw-button-content.spec.ts +9 -12
- package/src/adw-button-row.spec.ts +2 -4
- package/src/adw-carousel.spec.ts +40 -53
- package/src/adw-checks.spec.ts +36 -47
- package/src/adw-drop-down.spec.ts +25 -32
- package/src/adw-header-bar.spec.ts +5 -7
- package/src/adw-icon.spec.ts +23 -32
- package/src/adw-progress-bar.spec.ts +10 -12
- package/src/adw-row-state.spec.ts +9 -10
- package/src/adw-shortcut-label.spec.ts +112 -0
- package/src/adw-sidebar.spec.ts +17 -24
- package/src/adw-switch.spec.ts +11 -17
- package/src/adw-tab-view.spec.ts +7 -10
- package/src/adw-toast-overlay.spec.ts +7 -11
- package/src/adw-view-switcher-bar.spec.ts +10 -14
- package/src/adw-wrap-box.spec.ts +25 -36
- package/src/bottom-sheet.spec.ts +30 -36
- package/src/breakpoints.ts +15 -18
- package/src/chrome.spec.ts +13 -21
- package/src/elements/adw-about-dialog.ts +71 -114
- package/src/elements/adw-action-row.ts +22 -37
- package/src/elements/adw-alert-dialog.ts +25 -50
- package/src/elements/adw-avatar.ts +40 -15
- package/src/elements/adw-banner.ts +14 -18
- package/src/elements/adw-bottom-sheet.ts +31 -52
- package/src/elements/adw-button-content.ts +30 -37
- package/src/elements/adw-button-row.ts +14 -24
- package/src/elements/adw-carousel.ts +87 -148
- package/src/elements/adw-checks.ts +43 -56
- package/src/elements/adw-clamp.ts +8 -9
- package/src/elements/adw-combo-row.ts +17 -25
- package/src/elements/adw-data-grid.ts +26 -38
- package/src/elements/adw-dialog.ts +25 -56
- package/src/elements/adw-drop-down.ts +31 -51
- package/src/elements/adw-entry-row.ts +39 -46
- package/src/elements/adw-expander-row.ts +30 -53
- package/src/elements/adw-icon.ts +30 -53
- package/src/elements/adw-inline-view-switcher.ts +38 -67
- package/src/elements/adw-menu-button.ts +28 -58
- package/src/elements/adw-navigation-split-view.ts +35 -47
- package/src/elements/adw-navigation-view.ts +12 -28
- package/src/elements/adw-overlay-split-view.ts +100 -175
- package/src/elements/adw-password-entry-row.ts +18 -28
- package/src/elements/adw-popover.ts +28 -44
- package/src/elements/adw-preferences-dialog.ts +41 -66
- package/src/elements/adw-preferences-group.ts +33 -46
- package/src/elements/adw-progress-bar.ts +27 -47
- package/src/elements/adw-shortcut-label.ts +138 -0
- package/src/elements/adw-sidebar.ts +31 -39
- package/src/elements/adw-spin-row.ts +7 -14
- package/src/elements/adw-spinner.ts +31 -43
- package/src/elements/adw-split-button.ts +45 -75
- package/src/elements/adw-switch-row.ts +29 -46
- package/src/elements/adw-switch.ts +28 -47
- package/src/elements/adw-tab-view.ts +62 -103
- package/src/elements/adw-toast-overlay.ts +28 -35
- package/src/elements/adw-toggle-group.ts +9 -16
- package/src/elements/adw-view-stack.ts +32 -51
- package/src/elements/adw-view-switcher-bar.ts +26 -50
- package/src/elements/adw-view-switcher.ts +60 -110
- package/src/elements/adw-window-title.ts +4 -4
- package/src/elements/adw-wrap-box.ts +33 -59
- package/src/elements/view-switcher-dom.ts +15 -22
- package/src/entry-rows.spec.ts +18 -24
- package/src/index.ts +13 -15
- package/src/navigation-view.spec.ts +7 -10
- package/src/preferences-search.ts +11 -15
- package/src/preferences.spec.ts +13 -15
- package/src/source-view/adw-source-view.ts +6 -19
- package/src/source-view/hex.ts +7 -13
- package/src/split-button.spec.ts +32 -44
- package/src/split-views.spec.ts +83 -149
- package/src/style-classes.spec.ts +181 -0
- package/src/style-isolation.spec.ts +3 -6
- package/src/styles.generated.ts +1 -1
- package/src/tab-view.spec.ts +26 -35
- package/src/test.browser.mts +4 -0
- package/src/view-stack.spec.ts +23 -34
- 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
|
|
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
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
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
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
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
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
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
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
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
|
-
//
|
|
127
|
-
//
|
|
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
|
-
* `
|
|
148
|
-
*
|
|
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
|
-
//
|
|
204
|
-
//
|
|
205
|
-
// test that needs
|
|
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
|
-
//
|
|
210
|
-
//
|
|
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
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
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
|
-
//
|
|
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
|
|
267
|
-
//
|
|
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
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
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
|
-
*
|
|
305
|
-
* to —
|
|
306
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
*
|
|
439
|
-
*
|
|
440
|
-
*
|
|
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"
|
|
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
|
|
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`
|
|
475
|
-
//
|
|
476
|
-
//
|
|
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
|
|
495
|
-
//
|
|
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
|
|
506
|
-
//
|
|
507
|
-
//
|
|
508
|
-
//
|
|
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
|
|
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
|
-
*
|
|
640
|
-
*
|
|
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
|
|
644
|
-
*
|
|
645
|
-
*
|
|
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
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
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,
|