@gjsify/adwaita-web 0.31.0 → 0.33.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 (183) hide show
  1. package/dist/adwaita-web.css +835 -299
  2. package/dist/adwaita-web.css.map +1 -1
  3. package/lib/types/adw-about-dialog.spec.d.ts +1 -0
  4. package/lib/types/adw-action-rows.spec.d.ts +1 -0
  5. package/lib/types/adw-avatar.spec.d.ts +1 -0
  6. package/lib/types/adw-banner.spec.d.ts +1 -0
  7. package/lib/types/adw-button-content.spec.d.ts +1 -0
  8. package/lib/types/adw-carousel.spec.d.ts +1 -0
  9. package/lib/types/adw-checks.spec.d.ts +1 -0
  10. package/lib/types/adw-header-bar.spec.d.ts +1 -0
  11. package/lib/types/adw-icon.spec.d.ts +1 -0
  12. package/lib/types/adw-progress-bar.spec.d.ts +1 -0
  13. package/lib/types/adw-sidebar.spec.d.ts +1 -0
  14. package/lib/types/adw-switch.spec.d.ts +1 -0
  15. package/lib/types/adw-wrap-box.spec.d.ts +1 -0
  16. package/lib/types/bottom-sheet.spec.d.ts +1 -0
  17. package/lib/types/breakpoints.d.ts +22 -0
  18. package/lib/types/breakpoints.spec.d.ts +1 -0
  19. package/lib/types/chrome.spec.d.ts +1 -0
  20. package/lib/types/elements/adw-about-dialog.d.ts +47 -8
  21. package/lib/types/elements/adw-action-row.d.ts +35 -0
  22. package/lib/types/elements/adw-avatar.d.ts +11 -0
  23. package/lib/types/elements/adw-bottom-sheet.d.ts +33 -4
  24. package/lib/types/elements/adw-button-content.d.ts +12 -0
  25. package/lib/types/elements/adw-button-row.d.ts +10 -1
  26. package/lib/types/elements/adw-carousel.d.ts +111 -8
  27. package/lib/types/elements/adw-checks.d.ts +57 -0
  28. package/lib/types/elements/adw-clamp.d.ts +4 -1
  29. package/lib/types/elements/adw-combo-row.d.ts +10 -0
  30. package/lib/types/elements/adw-data-grid.d.ts +11 -31
  31. package/lib/types/elements/adw-drop-down.d.ts +17 -20
  32. package/lib/types/elements/adw-entry-row.d.ts +93 -3
  33. package/lib/types/elements/adw-expander-row.d.ts +7 -1
  34. package/lib/types/elements/adw-header-bar.d.ts +15 -0
  35. package/lib/types/elements/adw-icon.d.ts +25 -0
  36. package/lib/types/elements/adw-inline-view-switcher.d.ts +73 -11
  37. package/lib/types/elements/adw-menu-button.d.ts +6 -6
  38. package/lib/types/elements/adw-navigation-split-view.d.ts +48 -0
  39. package/lib/types/elements/adw-navigation-view.d.ts +63 -20
  40. package/lib/types/elements/adw-overlay-split-view.d.ts +94 -0
  41. package/lib/types/elements/adw-password-entry-row.d.ts +19 -10
  42. package/lib/types/elements/adw-popover.d.ts +58 -0
  43. package/lib/types/elements/adw-preferences-dialog.d.ts +57 -2
  44. package/lib/types/elements/adw-preferences-group.d.ts +31 -0
  45. package/lib/types/elements/adw-progress-bar.d.ts +38 -0
  46. package/lib/types/elements/adw-sidebar.d.ts +37 -5
  47. package/lib/types/elements/adw-spinner.d.ts +23 -0
  48. package/lib/types/elements/adw-split-button.d.ts +53 -7
  49. package/lib/types/elements/adw-switch-row.d.ts +11 -2
  50. package/lib/types/elements/adw-switch.d.ts +15 -0
  51. package/lib/types/elements/adw-tab-view.d.ts +129 -12
  52. package/lib/types/elements/adw-toolbar-view.d.ts +5 -0
  53. package/lib/types/elements/adw-view-stack.d.ts +39 -19
  54. package/lib/types/elements/adw-view-switcher-bar.d.ts +25 -7
  55. package/lib/types/elements/adw-view-switcher.d.ts +76 -13
  56. package/lib/types/elements/adw-window-title.d.ts +3 -1
  57. package/lib/types/elements/adw-wrap-box.d.ts +58 -3
  58. package/lib/types/elements/view-switcher-dom.d.ts +44 -0
  59. package/lib/types/entry-rows.spec.d.ts +1 -0
  60. package/lib/types/index.d.ts +7 -0
  61. package/lib/types/navigation-view.spec.d.ts +1 -0
  62. package/lib/types/preferences-search.d.ts +20 -0
  63. package/lib/types/preferences.spec.d.ts +1 -0
  64. package/lib/types/split-button.spec.d.ts +1 -0
  65. package/lib/types/split-views.spec.d.ts +1 -0
  66. package/lib/types/styles.generated.d.ts +1 -1
  67. package/lib/types/tab-view.spec.d.ts +1 -0
  68. package/lib/types/view-stack.spec.d.ts +1 -0
  69. package/lib/types/view-switcher.spec.d.ts +1 -0
  70. package/package.json +6 -6
  71. package/scss/_banner.scss +13 -0
  72. package/scss/_bottom_sheet.scss +5 -6
  73. package/scss/_button.scss +3 -26
  74. package/scss/_button_content.scss +28 -0
  75. package/scss/_checks.scss +228 -0
  76. package/scss/_clamp.scss +9 -3
  77. package/scss/_combo_row.scss +19 -0
  78. package/scss/_data_grid.scss +15 -7
  79. package/scss/_drop_down.scss +12 -55
  80. package/scss/_expander_row.scss +5 -50
  81. package/scss/_icon.scss +51 -0
  82. package/scss/_icons.generated.scss +6 -0
  83. package/scss/_inline_view_switcher.scss +34 -0
  84. package/scss/_labels.scss +135 -0
  85. package/scss/_menu_button.scss +10 -70
  86. package/scss/_navigation_split_view.scss +47 -8
  87. package/scss/_overlay_split_view.scss +117 -32
  88. package/scss/_popover.scss +186 -0
  89. package/scss/_preferences.scss +29 -0
  90. package/scss/_preferences_dialog.scss +17 -0
  91. package/scss/_progress_bar.scss +161 -0
  92. package/scss/_reset.scss +18 -7
  93. package/scss/_spinner.scss +37 -19
  94. package/scss/_split_button.scss +6 -50
  95. package/scss/_switch.scss +90 -0
  96. package/scss/_switch_row.scss +6 -52
  97. package/scss/_tab_view.scss +63 -0
  98. package/scss/_theme.scss +10 -0
  99. package/scss/_toolbar_view.scss +74 -0
  100. package/scss/_variables.scss +34 -0
  101. package/scss/_view_switcher.scss +40 -0
  102. package/scss/_view_switcher_bar.scss +37 -0
  103. package/scss/_wrap_box.scss +65 -6
  104. package/scss/adwaita-skin.scss +23 -0
  105. package/src/adw-about-dialog.spec.ts +350 -0
  106. package/src/adw-action-rows.spec.ts +342 -0
  107. package/src/adw-avatar.spec.ts +176 -0
  108. package/src/adw-banner.spec.ts +152 -0
  109. package/src/adw-button-content.spec.ts +207 -0
  110. package/src/adw-button-row.spec.ts +12 -6
  111. package/src/adw-carousel.spec.ts +389 -0
  112. package/src/adw-checks.spec.ts +368 -0
  113. package/src/adw-drop-down.spec.ts +123 -0
  114. package/src/adw-header-bar.spec.ts +83 -0
  115. package/src/adw-icon.spec.ts +167 -0
  116. package/src/adw-progress-bar.spec.ts +173 -0
  117. package/src/adw-row-state.spec.ts +49 -0
  118. package/src/adw-sidebar.spec.ts +332 -0
  119. package/src/adw-switch.spec.ts +242 -0
  120. package/src/adw-tab-view.spec.ts +12 -3
  121. package/src/adw-view-switcher-bar.spec.ts +61 -13
  122. package/src/adw-wrap-box.spec.ts +341 -0
  123. package/src/bottom-sheet.spec.ts +325 -0
  124. package/src/breakpoints.spec.ts +147 -0
  125. package/src/breakpoints.ts +67 -0
  126. package/src/chrome.spec.ts +400 -0
  127. package/src/elements/adw-about-dialog.ts +223 -163
  128. package/src/elements/adw-action-row.ts +131 -11
  129. package/src/elements/adw-avatar.ts +48 -54
  130. package/src/elements/adw-banner.ts +46 -10
  131. package/src/elements/adw-bottom-sheet.ts +145 -60
  132. package/src/elements/adw-button-content.ts +107 -33
  133. package/src/elements/adw-button-row.ts +61 -37
  134. package/src/elements/adw-button.ts +5 -7
  135. package/src/elements/adw-carousel.ts +467 -105
  136. package/src/elements/adw-checks.ts +299 -0
  137. package/src/elements/adw-clamp.ts +80 -10
  138. package/src/elements/adw-combo-row.ts +32 -7
  139. package/src/elements/adw-data-grid.ts +43 -91
  140. package/src/elements/adw-drop-down.ts +117 -128
  141. package/src/elements/adw-entry-row.ts +404 -36
  142. package/src/elements/adw-expander-row.ts +61 -29
  143. package/src/elements/adw-header-bar.ts +31 -6
  144. package/src/elements/adw-icon.ts +148 -0
  145. package/src/elements/adw-inline-view-switcher.ts +325 -131
  146. package/src/elements/adw-menu-button.ts +93 -70
  147. package/src/elements/adw-navigation-split-view.ts +220 -14
  148. package/src/elements/adw-navigation-view.ts +286 -148
  149. package/src/elements/adw-overlay-split-view.ts +536 -28
  150. package/src/elements/adw-password-entry-row.ts +111 -89
  151. package/src/elements/adw-popover.ts +283 -0
  152. package/src/elements/adw-preferences-dialog.ts +120 -21
  153. package/src/elements/adw-preferences-group.ts +128 -22
  154. package/src/elements/adw-progress-bar.ts +189 -0
  155. package/src/elements/adw-sidebar.ts +301 -142
  156. package/src/elements/adw-spin-row.ts +11 -5
  157. package/src/elements/adw-spinner.ts +168 -9
  158. package/src/elements/adw-split-button.ts +371 -92
  159. package/src/elements/adw-status-page.ts +9 -9
  160. package/src/elements/adw-switch-row.ts +100 -30
  161. package/src/elements/adw-switch.ts +129 -0
  162. package/src/elements/adw-tab-view.ts +700 -129
  163. package/src/elements/adw-toggle-group.ts +5 -7
  164. package/src/elements/adw-toolbar-view.ts +84 -21
  165. package/src/elements/adw-view-stack.ts +183 -85
  166. package/src/elements/adw-view-switcher-bar.ts +171 -81
  167. package/src/elements/adw-view-switcher.ts +328 -117
  168. package/src/elements/adw-window-title.ts +44 -11
  169. package/src/elements/adw-wrap-box.ts +329 -78
  170. package/src/elements/view-switcher-dom.ts +108 -0
  171. package/src/entry-rows.spec.ts +391 -0
  172. package/src/index.ts +23 -0
  173. package/src/navigation-view.spec.ts +435 -0
  174. package/src/preferences-search.ts +135 -0
  175. package/src/preferences.spec.ts +250 -0
  176. package/src/source-view/adw-source-view.ts +2 -5
  177. package/src/split-button.spec.ts +470 -0
  178. package/src/split-views.spec.ts +893 -0
  179. package/src/styles.generated.ts +1 -1
  180. package/src/tab-view.spec.ts +451 -0
  181. package/src/test.browser.mts +49 -0
  182. package/src/view-stack.spec.ts +272 -0
  183. package/src/view-switcher.spec.ts +665 -0
@@ -1,30 +1,189 @@
1
1
  // <adw-spinner> — A continuously-spinning loading indicator.
2
- // Attributes: size (px, default 24).
3
- // Reference: refs/adwaita-web/adwaita-web/scss/_spinner.scss
4
- // Reference: refs/libadwaita (Adw.Spinner)
2
+ // Attributes: size (px; the BOX, floored at the measured minimum 16).
3
+ //
4
+ // THE BOX AND THE RING ARE DIFFERENT THINGS. `adw_spinner_measure`
5
+ // (adw-spinner.c:78-81) reports MIN_SIZE as both minimum and natural and has no
6
+ // upper bound — `MAX_SIZE` at :15 is defined and never referenced — while
7
+ // `adw_spinner_snapshot` (:95-99) hands the widget's real width and height to
8
+ // the paintable, which caps only `radius` (adw-spinner-paintable.c:343) and
9
+ // still centres on the box (:349-351). So `size="200"` occupies 200px of layout
10
+ // and draws a 64px ring in the middle. This element used to BE the ring, which
11
+ // is why its suite asserted the opposite of the core's `SPINNER_SIZE_VECTORS`.
12
+ //
13
+ // THE ARC IS NOT A ROTATING QUARTER-CIRCLE. It extends, overlaps, contracts and
14
+ // idles on an ease-in-out-sine while the figure turns; the arithmetic is
15
+ // `@gjsify/adwaita-core`'s `spinnerArc`, shared with the vectors that judge it.
16
+ // Expressing that needs a per-frame value, so this element draws an SVG arc and
17
+ // advances it from one module-level ticker — not one timer per spinner. CSS
18
+ // keyframes cannot express it: a `border-top-color` chase is a fixed 90 degrees,
19
+ // which is what this element drew for its whole life.
20
+ //
21
+ // IT KEEPS SPINNING UNDER REDUCED MOTION. `adw_spinner_paintable_set_widget`
22
+ // calls `adw_animation_set_follow_enable_animations_setting (…, FALSE)` (:537)
23
+ // — deliberately, because a frozen busy indicator reads as a hang. The old
24
+ // `@media (prefers-reduced-motion: reduce) { animation: none }` did exactly that.
25
+ //
26
+ // Reference: refs/libadwaita/src/adw-spinner.c (MIN_SIZE, adw_spinner_measure, the a11y role)
27
+ // Reference: refs/libadwaita/src/adw-spinner-paintable.c (the animation + geometry)
5
28
  // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
6
29
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
7
30
 
31
+ import {
32
+ ADW_SPINNER_STILL_PROGRESS,
33
+ ADW_SPINNER_TRACK_OPACITY,
34
+ resolveSpinnerSize,
35
+ spinnerArc,
36
+ spinnerGeometry,
37
+ spinnerProgressAt,
38
+ } from '@gjsify/adwaita-core';
39
+
40
+ const SVG_NS = 'http://www.w3.org/2000/svg';
41
+
42
+ /**
43
+ * Every mapped spinner, driven by ONE `requestAnimationFrame` loop.
44
+ *
45
+ * The C animates per widget off the frame clock, which costs nothing extra
46
+ * because the clock is already ticking. A browser has no such clock, so the
47
+ * equivalent is one shared rAF: N spinners on a page must not mean N loops, and
48
+ * the loop must not exist at all while none are mapped.
49
+ */
50
+ const mapped = new Set<AdwSpinner>();
51
+ let frameHandle = 0;
52
+
53
+ function tick(now: number): void {
54
+ for (const spinner of mapped) spinner.drawAt(now);
55
+ frameHandle = mapped.size > 0 ? requestAnimationFrame(tick) : 0;
56
+ }
57
+
58
+ function startTicking(): void {
59
+ if (frameHandle === 0 && mapped.size > 0) frameHandle = requestAnimationFrame(tick);
60
+ }
61
+
8
62
  export class AdwSpinner extends HTMLElement {
9
63
  static get observedAttributes() {
10
64
  return ['size'];
11
65
  }
12
66
 
67
+ private _svg: SVGSVGElement | null = null;
68
+ private _track: SVGCircleElement | null = null;
69
+ private _arc: SVGCircleElement | null = null;
70
+ /** Path length of the ring, so the dash arithmetic is done once per resize. */
71
+ private _circumference = 0;
72
+ /** Ring radius in px — the dash lengths are arc-length, i.e. radians × r. */
73
+ private _radius = 0;
74
+ /** The timestamp this spinner was mapped at, so its progress starts at 0. */
75
+ private _origin: number | null = null;
76
+
13
77
  connectedCallback() {
14
- this._sync();
78
+ this._build();
79
+ // `widget_map_cb` (adw-spinner-paintable.c:181-185) plays the animation
80
+ // on MAP, not on construction: an off-screen spinner burns nothing.
81
+ mapped.add(this);
82
+ this._origin = null;
83
+ startTicking();
84
+ }
85
+
86
+ disconnectedCallback() {
87
+ mapped.delete(this);
15
88
  }
16
89
 
17
90
  attributeChangedCallback() {
18
91
  this._sync();
19
92
  }
20
93
 
21
- private _sync() {
22
- const size = parseFloat(this.getAttribute('size') || '24');
94
+ /**
95
+ * Draw the frame for `now`, in `requestAnimationFrame` timebase.
96
+ *
97
+ * Public because the shared ticker is a module-level function rather than a
98
+ * method — and because a test needs to place the spinner at a known moment
99
+ * without waiting for real frames.
100
+ */
101
+ drawAt(now: number): void {
102
+ if (this._origin === null) this._origin = now;
103
+ this._paint(spinnerProgressAt(now - this._origin));
104
+ }
105
+
106
+ private _build(): void {
107
+ if (this._svg) return;
108
+ const svg = document.createElementNS(SVG_NS, 'svg');
109
+ svg.setAttribute('fill', 'none');
110
+ // The ring is decorative; the ROLE is on the host, per adw-spinner.c:124.
111
+ svg.setAttribute('aria-hidden', 'true');
112
+
113
+ const track = document.createElementNS(SVG_NS, 'circle');
114
+ track.setAttribute('stroke', 'currentColor');
115
+ // `CIRCLE_OPACITY` of the WIDGET's colour (adw-spinner-paintable.c:367-369),
116
+ // not a hardcoded grey — so the track follows the text colour everywhere.
117
+ track.setAttribute('stroke-opacity', String(ADW_SPINNER_TRACK_OPACITY));
118
+
119
+ const arc = document.createElementNS(SVG_NS, 'circle');
120
+ arc.setAttribute('stroke', 'currentColor');
121
+ // `GSK_LINE_CAP_ROUND` (adw-spinner-paintable.c:354). The port's
122
+ // `border-top-color` ends were square-cut, visible from 48px up.
123
+ arc.setAttribute('stroke-linecap', 'round');
124
+
125
+ svg.append(track, arc);
126
+ this._svg = svg;
127
+ this._track = track;
128
+ this._arc = arc;
129
+ this.replaceChildren(svg);
130
+
131
+ // `gtk_widget_class_set_accessible_role (…, PROGRESS_BAR)` (adw-spinner.c:124)
132
+ // and `GTK_ACCESSIBLE_STATE_BUSY, TRUE` (:139-141). A repo-wide grep for
133
+ // either found ZERO hits before this: screen readers announced nothing.
134
+ this.setAttribute('role', 'progressbar');
135
+ this.setAttribute('aria-busy', 'true');
136
+
137
+ this._sync();
138
+ }
139
+
140
+ /** Re-derive the box, the ring and the stroke from the `size` attribute. */
141
+ private _sync(): void {
142
+ const svg = this._svg;
143
+ const track = this._track;
144
+ const arc = this._arc;
145
+ if (!svg || !track || !arc) return;
146
+
147
+ const size = resolveSpinnerSize(this.getAttribute('size'));
148
+ const { diameter, lineWidth } = spinnerGeometry(size, size);
149
+ // THE BOX: whatever was asked for, floored at the measured minimum.
23
150
  this.style.width = `${size}px`;
24
151
  this.style.height = `${size}px`;
25
- // Scale the ring thickness with the diameter (libadwaita's arc thickens
26
- // with size); clamp so tiny spinners stay visible.
27
- this.style.borderWidth = `${Math.max(2, Math.round(size / 12))}px`;
152
+ // THE RING: capped at 64, centred by the host's flex box.
153
+ svg.setAttribute('width', String(diameter));
154
+ svg.setAttribute('height', String(diameter));
155
+ svg.setAttribute('viewBox', `0 0 ${diameter} ${diameter}`);
156
+
157
+ // The stroke is centred on the path, so the circle sits half a stroke in
158
+ // — `radius - line_width / 2` (adw-spinner-paintable.c:364).
159
+ const radius = (diameter - lineWidth) / 2;
160
+ this._radius = radius;
161
+ this._circumference = 2 * Math.PI * radius;
162
+ for (const circle of [track, arc]) {
163
+ circle.setAttribute('cx', String(diameter / 2));
164
+ circle.setAttribute('cy', String(diameter / 2));
165
+ circle.setAttribute('r', String(radius));
166
+ circle.setAttribute('stroke-width', String(lineWidth));
167
+ }
168
+ // A resize while unmapped still has to leave a drawable frame behind:
169
+ // the resting pose, which is what a paintable without an animation draws.
170
+ this._paint(this._origin === null ? ADW_SPINNER_STILL_PROGRESS : this._lastProgress);
171
+ }
172
+
173
+ /** The progress the last painted frame used, so a resize can repaint it. */
174
+ private _lastProgress = ADW_SPINNER_STILL_PROGRESS;
175
+
176
+ private _paint(progress: number): void {
177
+ const arc = this._arc;
178
+ if (!arc || this._radius <= 0) return;
179
+ this._lastProgress = progress;
180
+ const { end, length } = spinnerArc(progress);
181
+ const drawn = length * this._radius;
182
+ arc.setAttribute('stroke-dasharray', `${drawn} ${Math.max(this._circumference - drawn, 0)}`);
183
+ // An SVG circle's path starts at 3 o'clock and runs clockwise, which is
184
+ // the same origin and direction the C's angles use — so a radian is a
185
+ // path distance and the dash only has to be shifted to `end`.
186
+ arc.setAttribute('stroke-dashoffset', String(-end * this._radius));
28
187
  }
29
188
  }
30
189