@gjsify/adwaita-web 0.30.0 → 0.32.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 (176) hide show
  1. package/dist/adwaita-web.css +786 -272
  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-data-grid.d.ts +11 -31
  30. package/lib/types/elements/adw-drop-down.d.ts +17 -20
  31. package/lib/types/elements/adw-entry-row.d.ts +93 -3
  32. package/lib/types/elements/adw-expander-row.d.ts +7 -1
  33. package/lib/types/elements/adw-header-bar.d.ts +15 -0
  34. package/lib/types/elements/adw-icon.d.ts +25 -0
  35. package/lib/types/elements/adw-inline-view-switcher.d.ts +37 -11
  36. package/lib/types/elements/adw-menu-button.d.ts +6 -6
  37. package/lib/types/elements/adw-navigation-split-view.d.ts +6 -0
  38. package/lib/types/elements/adw-navigation-view.d.ts +63 -20
  39. package/lib/types/elements/adw-overlay-split-view.d.ts +38 -0
  40. package/lib/types/elements/adw-password-entry-row.d.ts +19 -10
  41. package/lib/types/elements/adw-popover.d.ts +58 -0
  42. package/lib/types/elements/adw-preferences-dialog.d.ts +57 -2
  43. package/lib/types/elements/adw-preferences-group.d.ts +31 -0
  44. package/lib/types/elements/adw-progress-bar.d.ts +38 -0
  45. package/lib/types/elements/adw-sidebar.d.ts +37 -5
  46. package/lib/types/elements/adw-split-button.d.ts +53 -7
  47. package/lib/types/elements/adw-switch-row.d.ts +11 -2
  48. package/lib/types/elements/adw-switch.d.ts +15 -0
  49. package/lib/types/elements/adw-tab-view.d.ts +129 -12
  50. package/lib/types/elements/adw-toolbar-view.d.ts +5 -0
  51. package/lib/types/elements/adw-view-stack.d.ts +27 -19
  52. package/lib/types/elements/adw-view-switcher-bar.d.ts +23 -7
  53. package/lib/types/elements/adw-view-switcher.d.ts +22 -11
  54. package/lib/types/elements/adw-window-title.d.ts +3 -1
  55. package/lib/types/elements/view-switcher-dom.d.ts +44 -0
  56. package/lib/types/entry-rows.spec.d.ts +1 -0
  57. package/lib/types/index.d.ts +7 -0
  58. package/lib/types/navigation-view.spec.d.ts +1 -0
  59. package/lib/types/preferences-search.d.ts +20 -0
  60. package/lib/types/preferences.spec.d.ts +1 -0
  61. package/lib/types/split-button.spec.d.ts +1 -0
  62. package/lib/types/split-views.spec.d.ts +1 -0
  63. package/lib/types/styles.generated.d.ts +1 -1
  64. package/lib/types/tab-view.spec.d.ts +1 -0
  65. package/lib/types/view-stack.spec.d.ts +1 -0
  66. package/lib/types/view-switcher.spec.d.ts +1 -0
  67. package/package.json +6 -6
  68. package/scss/_banner.scss +13 -0
  69. package/scss/_bottom_sheet.scss +5 -6
  70. package/scss/_button.scss +3 -26
  71. package/scss/_button_content.scss +28 -0
  72. package/scss/_checks.scss +228 -0
  73. package/scss/_clamp.scss +9 -3
  74. package/scss/_data_grid.scss +15 -7
  75. package/scss/_drop_down.scss +12 -55
  76. package/scss/_expander_row.scss +5 -50
  77. package/scss/_icon.scss +51 -0
  78. package/scss/_icons.generated.scss +6 -0
  79. package/scss/_inline_view_switcher.scss +34 -0
  80. package/scss/_labels.scss +135 -0
  81. package/scss/_menu_button.scss +10 -70
  82. package/scss/_popover.scss +186 -0
  83. package/scss/_preferences.scss +29 -0
  84. package/scss/_preferences_dialog.scss +17 -0
  85. package/scss/_progress_bar.scss +161 -0
  86. package/scss/_reset.scss +18 -7
  87. package/scss/_spinner.scss +7 -3
  88. package/scss/_split_button.scss +6 -50
  89. package/scss/_switch.scss +90 -0
  90. package/scss/_switch_row.scss +6 -52
  91. package/scss/_tab_view.scss +64 -0
  92. package/scss/_theme.scss +10 -0
  93. package/scss/_toolbar_view.scss +74 -0
  94. package/scss/_variables.scss +34 -0
  95. package/scss/_view_switcher.scss +40 -0
  96. package/scss/_view_switcher_bar.scss +37 -0
  97. package/scss/_wrap_box.scss +56 -6
  98. package/scss/adwaita-skin.scss +23 -0
  99. package/src/adw-about-dialog.spec.ts +350 -0
  100. package/src/adw-action-rows.spec.ts +342 -0
  101. package/src/adw-avatar.spec.ts +139 -0
  102. package/src/adw-banner.spec.ts +152 -0
  103. package/src/adw-button-content.spec.ts +183 -0
  104. package/src/adw-button-row.spec.ts +12 -6
  105. package/src/adw-carousel.spec.ts +389 -0
  106. package/src/adw-checks.spec.ts +368 -0
  107. package/src/adw-drop-down.spec.ts +123 -0
  108. package/src/adw-header-bar.spec.ts +83 -0
  109. package/src/adw-icon.spec.ts +167 -0
  110. package/src/adw-progress-bar.spec.ts +173 -0
  111. package/src/adw-sidebar.spec.ts +332 -0
  112. package/src/adw-switch.spec.ts +242 -0
  113. package/src/adw-tab-view.spec.ts +12 -3
  114. package/src/adw-view-switcher-bar.spec.ts +61 -13
  115. package/src/adw-wrap-box.spec.ts +194 -0
  116. package/src/bottom-sheet.spec.ts +325 -0
  117. package/src/breakpoints.spec.ts +147 -0
  118. package/src/breakpoints.ts +67 -0
  119. package/src/chrome.spec.ts +301 -0
  120. package/src/elements/adw-about-dialog.ts +223 -163
  121. package/src/elements/adw-action-row.ts +120 -10
  122. package/src/elements/adw-avatar.ts +48 -54
  123. package/src/elements/adw-banner.ts +46 -10
  124. package/src/elements/adw-bottom-sheet.ts +145 -60
  125. package/src/elements/adw-button-content.ts +107 -33
  126. package/src/elements/adw-button-row.ts +61 -37
  127. package/src/elements/adw-button.ts +5 -7
  128. package/src/elements/adw-carousel.ts +467 -105
  129. package/src/elements/adw-checks.ts +299 -0
  130. package/src/elements/adw-clamp.ts +80 -10
  131. package/src/elements/adw-combo-row.ts +15 -7
  132. package/src/elements/adw-data-grid.ts +43 -91
  133. package/src/elements/adw-drop-down.ts +117 -128
  134. package/src/elements/adw-entry-row.ts +404 -36
  135. package/src/elements/adw-expander-row.ts +61 -29
  136. package/src/elements/adw-header-bar.ts +31 -6
  137. package/src/elements/adw-icon.ts +148 -0
  138. package/src/elements/adw-inline-view-switcher.ts +240 -129
  139. package/src/elements/adw-menu-button.ts +93 -70
  140. package/src/elements/adw-navigation-split-view.ts +48 -7
  141. package/src/elements/adw-navigation-view.ts +286 -148
  142. package/src/elements/adw-overlay-split-view.ts +164 -14
  143. package/src/elements/adw-password-entry-row.ts +111 -89
  144. package/src/elements/adw-popover.ts +283 -0
  145. package/src/elements/adw-preferences-dialog.ts +120 -21
  146. package/src/elements/adw-preferences-group.ts +128 -22
  147. package/src/elements/adw-progress-bar.ts +189 -0
  148. package/src/elements/adw-sidebar.ts +301 -142
  149. package/src/elements/adw-spin-row.ts +11 -5
  150. package/src/elements/adw-spinner.ts +23 -8
  151. package/src/elements/adw-split-button.ts +371 -92
  152. package/src/elements/adw-status-page.ts +9 -9
  153. package/src/elements/adw-switch-row.ts +100 -30
  154. package/src/elements/adw-switch.ts +129 -0
  155. package/src/elements/adw-tab-view.ts +682 -129
  156. package/src/elements/adw-toggle-group.ts +5 -7
  157. package/src/elements/adw-toolbar-view.ts +84 -21
  158. package/src/elements/adw-view-stack.ts +162 -85
  159. package/src/elements/adw-view-switcher-bar.ts +163 -81
  160. package/src/elements/adw-view-switcher.ts +231 -112
  161. package/src/elements/adw-window-title.ts +44 -11
  162. package/src/elements/adw-wrap-box.ts +131 -35
  163. package/src/elements/view-switcher-dom.ts +108 -0
  164. package/src/entry-rows.spec.ts +391 -0
  165. package/src/index.ts +23 -0
  166. package/src/navigation-view.spec.ts +435 -0
  167. package/src/preferences-search.ts +135 -0
  168. package/src/preferences.spec.ts +250 -0
  169. package/src/source-view/adw-source-view.ts +2 -5
  170. package/src/split-button.spec.ts +470 -0
  171. package/src/split-views.spec.ts +309 -0
  172. package/src/styles.generated.ts +1 -1
  173. package/src/tab-view.spec.ts +451 -0
  174. package/src/test.browser.mts +49 -0
  175. package/src/view-stack.spec.ts +272 -0
  176. package/src/view-switcher.spec.ts +446 -0
@@ -0,0 +1,161 @@
1
+ // _progress_bar.scss — <adw-progress-bar>, the determinate partner to
2
+ // <adw-spinner>.
3
+ //
4
+ // TWO SOURCES, AND WHICH HALF CAME FROM WHICH — the two disagree, so this is not
5
+ // bookkeeping:
6
+ //
7
+ // GEOMETRY + COLOUR + THE OSD VARIANT come from
8
+ // `refs/libadwaita/src/stylesheet/widgets/_progress-bar.scss`: an 8px trough
9
+ // (:6), the 99px `$_progress-radius` (:33-35), the `%scale_trough` /
10
+ // `%scale_highlight` placeholders it shares with the scale
11
+ // (`_scale.scss:1-17`), the `> trough.empty > progress { all: unset }` rule
12
+ // that makes a zero fraction draw NOTHING rather than a 0px sliver (:85), and
13
+ // the `.osd` variant — a 2px bar with no trough, for under a header bar
14
+ // (:59-83).
15
+ //
16
+ // THE INDETERMINATE ANIMATION comes from
17
+ // `refs/adwaita-web/adwaita-web/scss/_progressbar.scss:25-66`, because
18
+ // libadwaita has NO CSS equivalent: GTK animates a pulsing block from C
19
+ // (`gtk_progress_bar_pulse`), so the stylesheet has nothing to copy. Its
20
+ // keyframes and its `prefers-reduced-motion` fallback are the only parts taken
21
+ // from there. Its GEOMETRY is NOT: it draws a 6px bar with a 3px radius and
22
+ // has no trough placeholder, no OSD variant and no text node, so copying its
23
+ // numbers would put a bar in this package that matches neither source.
24
+ //
25
+ // NOT PORTED, deliberately: `progressbar.vertical` (:10-15) and the four
26
+ // `progress.{left,right,top,bottom}` corner-radius rules (:37-55). Both exist
27
+ // for orientations and trough-splitting `<adw-progress-bar>` does not expose —
28
+ // there is no `orientation` attribute — and a rule nothing can ever select is a
29
+ // rule that rots.
30
+ //
31
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_progress-bar.scss:5-6,17-21,23-25,27-35,59-85
32
+ // Reference: refs/libadwaita/src/stylesheet/_scale.scss:1-17 (%scale_trough, %scale_highlight)
33
+ // Reference: refs/libadwaita/src/stylesheet/_colors.scss:280-286 (the trough colours)
34
+ // Reference: refs/adwaita-web/adwaita-web/scss/_progressbar.scss:25-66 (indeterminate keyframes + reduced-motion fallback ONLY)
35
+ // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
36
+ // Copyright (c) 2025 csm (adwaita-web). MIT License.
37
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
38
+
39
+ // `.dimmed` / `.numeric`, which the text node @extends exactly as upstream does.
40
+ @use 'labels';
41
+
42
+ adw-progress-bar {
43
+ display: flex;
44
+ flex-direction: column;
45
+ gap: var(--spacing-xs);
46
+ // `progressbar.horizontal > trough { min-width: 150px }` (:5) is a WIDGET
47
+ // minimum in GTK, so it belongs on the element rather than on the trough.
48
+ min-width: 150px;
49
+
50
+ .adw-progress-bar-trough {
51
+ // %scale_trough (_scale.scss:1-10)
52
+ position: relative;
53
+ display: flex;
54
+ overflow: hidden;
55
+ height: 8px; // :6 — `&, > progress { min-height: 8px }`
56
+ border-radius: 99px;
57
+ background-color: color-mix(in srgb, currentColor 15%, transparent);
58
+ transition: background 200ms ease-out;
59
+
60
+ @media (prefers-contrast: more) {
61
+ // $trough_color_hc (_colors.scss:284)
62
+ background-color: color-mix(in srgb, currentColor 30%, transparent);
63
+ }
64
+ }
65
+
66
+ .adw-progress-bar-progress {
67
+ // %scale_highlight (_scale.scss:12-17) + $_progress-radius (:33-35)
68
+ height: 100%;
69
+ border-radius: 99px;
70
+ background-color: var(--accent-bg-color);
71
+ color: var(--accent-fg-color);
72
+ transition:
73
+ width 200ms ease-out,
74
+ background 200ms ease-out;
75
+ }
76
+
77
+ // `> text { @extend .dimmed; @extend .numeric; font-size: smaller; }` (:17-21)
78
+ // — literally upstream's three lines, now that `.dimmed` and `.numeric` exist
79
+ // here as the same utility classes they are there.
80
+ .adw-progress-bar-text {
81
+ @extend .dimmed;
82
+ @extend .numeric;
83
+
84
+ font-size: smaller;
85
+ }
86
+
87
+ // `&:disabled { filter: Opacity(var(--disabled-opacity)) }` (:23-25). This
88
+ // package defines no `--disabled-opacity`, so `--dim-opacity` stands in — the
89
+ // same substitution `_switch.scss` documents, not a fourth invented token.
90
+ &[disabled] {
91
+ opacity: var(--dim-opacity);
92
+ }
93
+
94
+ // Fill from the far end. GTK spells this `:inverted`; flexbox handles the
95
+ // writing direction, so nothing here needs an RTL branch.
96
+ &[inverted] .adw-progress-bar-trough {
97
+ justify-content: flex-end;
98
+ }
99
+
100
+ // `> trough.empty > progress { all: unset }` (:85) — at fraction 0 the
101
+ // indicator DISAPPEARS instead of drawing a rounded 0px stub.
102
+ .adw-progress-bar-trough.empty .adw-progress-bar-progress {
103
+ all: unset;
104
+ }
105
+
106
+ // The `.osd` variant (:59-83): a hairline bar with no trough at all, the way
107
+ // it is drawn under a header bar.
108
+ &[osd] {
109
+ min-width: 2px;
110
+
111
+ .adw-progress-bar-trough {
112
+ height: 2px;
113
+ border-radius: 0;
114
+ background-color: transparent;
115
+ box-shadow: none;
116
+ }
117
+
118
+ .adw-progress-bar-progress {
119
+ border-radius: 0;
120
+ }
121
+ }
122
+
123
+ // Indeterminate. The block leaves the flex flow and bounces across the trough;
124
+ // this is the ONLY part of the widget taken from the vendored web port, since
125
+ // GTK pulses from C and its stylesheet has no equivalent to copy.
126
+ &[pulsing] .adw-progress-bar-progress {
127
+ position: absolute;
128
+ inset-block: 0;
129
+ width: 30%;
130
+ animation: adw-progress-bar-indeterminate 1.5s infinite ease-in-out;
131
+
132
+ // `_progressbar.scss:42-49` — with motion suppressed the block stops moving
133
+ // and fills the trough, so the bar still reads as "busy" and not as "0%".
134
+ @media (prefers-reduced-motion: reduce) {
135
+ left: 0;
136
+ width: 100%;
137
+ animation: none;
138
+ }
139
+ }
140
+ }
141
+
142
+ // refs/adwaita-web/adwaita-web/scss/_progressbar.scss:53-66, verbatim offsets.
143
+ // `left` rather than `inset-inline-start`: the port animates a physical offset,
144
+ // and a keyframe that flipped with the writing direction would no longer be the
145
+ // animation being cited.
146
+ @keyframes adw-progress-bar-indeterminate {
147
+ 0% {
148
+ left: -35%;
149
+ width: 30%;
150
+ }
151
+
152
+ 50% {
153
+ left: 50%;
154
+ width: 40%;
155
+ }
156
+
157
+ 100% {
158
+ left: 105%;
159
+ width: 30%;
160
+ }
161
+ }
package/scss/_reset.scss CHANGED
@@ -17,20 +17,31 @@
17
17
  // inherited typography + a host `* {}` box-sizing reset, which is what this
18
18
  // neutralises.
19
19
 
20
- // Every custom element adwaita-web defines. Keep in sync with
21
- // `src/elements/*` (the `customElements.define('adw-…')` calls).
20
+ // Every custom element adwaita-web defines — one entry per `customElements
21
+ // .define('adw-…')` call under `src/`.
22
+ //
23
+ // DERIVED, NOT REMEMBERED: `scripts/check-adwaita-reset-components.mjs` walks
24
+ // those calls and fails on any tag missing from this list (and on any entry with
25
+ // no call behind it). A hand-kept list is a second copy of the registry, and it
26
+ // had already drifted — `adw-source-view` was defined for its whole life and
27
+ // never listed, so it silently ran without the isolation floor. Nothing noticed,
28
+ // because the only spec touching this file instantiates `adw-switch-row`.
22
29
  $adw-components:
23
30
  adw-about-dialog, adw-action-row, adw-alert-dialog, adw-alert-response,
24
31
  adw-avatar, adw-banner, adw-bottom-sheet, adw-bottom-sheet-content,
25
32
  adw-bottom-sheet-sheet, adw-button, adw-button-content, adw-button-row,
26
33
  adw-card, adw-carousel, adw-carousel-indicator-dots,
27
- adw-carousel-indicator-lines, adw-clamp, adw-combo-row, adw-data-grid,
34
+ adw-carousel-indicator-lines, adw-checkbox, adw-clamp, adw-combo-row,
35
+ adw-data-grid,
28
36
  adw-dialog, adw-drop-down, adw-entry, adw-entry-row, adw-expander-row,
29
- adw-header-bar, adw-inline-view-switcher, adw-menu-button, adw-navigation-page,
37
+ adw-header-bar, adw-icon, adw-inline-view-switcher, adw-menu-button,
38
+ adw-navigation-page,
30
39
  adw-navigation-split-view, adw-navigation-view, adw-overlay-split-view,
31
- adw-password-entry-row, adw-preferences-dialog, adw-preferences-group,
32
- adw-preferences-page, adw-sidebar, adw-sidebar-item, adw-sidebar-section,
33
- adw-spinner, adw-spin-row, adw-split-button, adw-status-page, adw-switch-row,
40
+ adw-password-entry-row, adw-popover, adw-preferences-dialog,
41
+ adw-preferences-group, adw-preferences-page, adw-progress-bar, adw-radio,
42
+ adw-sidebar, adw-sidebar-item,
43
+ adw-sidebar-section, adw-source-view, adw-spinner, adw-spin-row,
44
+ adw-split-button, adw-status-page, adw-switch, adw-switch-row,
34
45
  adw-tab-page, adw-tab-view, adw-toast-overlay, adw-toggle, adw-toggle-group,
35
46
  adw-toolbar-view, adw-view-stack, adw-view-stack-page, adw-view-switcher,
36
47
  adw-view-switcher-bar, adw-view-switcher-page, adw-window, adw-window-title,
@@ -7,11 +7,15 @@
7
7
  adw-spinner {
8
8
  display: inline-block;
9
9
  box-sizing: border-box;
10
- width: 24px;
11
- height: 24px;
10
+ // Adw.Spinner measures 16 as BOTH its minimum and its natural size
11
+ // (adw-spinner.c:78-81), stroked at the documented "2px for 16px". The element
12
+ // overwrites both from `spinnerGeometry` when it upgrades; these are the values
13
+ // in force until then — the 24px/3px they replace were not from any source.
14
+ width: 16px;
15
+ height: 16px;
12
16
  // Neutral arc (currentColor, theme-aware) over a faint track — Adw.Spinner
13
17
  // is a neutral indicator, NOT accent-coloured.
14
- border: 3px solid rgba(127, 127, 127, 0.25);
18
+ border: 2px solid rgba(127, 127, 127, 0.25);
15
19
  border-top-color: currentColor;
16
20
  border-radius: 50%;
17
21
  animation: adw-spinner-spin 0.8s linear infinite;
@@ -111,56 +111,12 @@
111
111
  }
112
112
  }
113
113
 
114
- // --- Dropdown menu (popover) ---
115
- .adw-split-button-menu {
116
- position: absolute;
117
- top: calc(100% + 4px);
118
- right: 0;
119
- z-index: 10;
120
- display: flex;
121
- flex-direction: column;
122
- min-width: 160px;
123
- padding: var(--spacing-xs);
124
- border-radius: var(--button-radius);
125
- background-color: var(--popover-bg-color, var(--window-bg-color, #fff));
126
- color: var(--window-fg-color);
127
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 0 0 1px var(--separator-color);
128
-
129
- &[hidden] {
130
- display: none;
131
- }
132
- }
133
-
134
- .adw-split-button-menu-item {
135
- box-sizing: border-box;
136
- display: flex;
137
- align-items: center;
138
- width: 100%;
139
- min-height: 32px;
140
- margin: 0;
141
- padding: var(--spacing-xs) var(--spacing-s);
142
- border: none;
143
- border-radius: calc(var(--button-radius) - 2px);
144
- background-color: transparent;
145
- color: inherit;
146
- font: inherit;
147
- text-align: start;
148
- cursor: pointer;
149
- transition: background-color 0.1s ease;
150
-
151
- &:hover {
152
- background-color: var(--button-hover-color);
153
- }
154
-
155
- &:active {
156
- background-color: var(--button-active-color);
157
- }
158
-
159
- &:focus-visible {
160
- outline: 2px solid var(--accent-color);
161
- outline-offset: -2px;
162
- }
163
- }
114
+ // The dropdown menu is `<adw-popover>` (`_popover.scss`), and this was the
115
+ // WORST of the three hand-rolled surfaces: `--button-radius` (9px) where
116
+ // libadwaita's popover is 15px, under a two-layer shadow that exists nowhere
117
+ // in the vendored stylesheet (`popover > contents` has three,
118
+ // _popovers.scss:18-20), and a `calc(var(--button-radius) - 2px)` (7px) row
119
+ // where `modelbutton` is 9px. Nothing element-specific was left to keep.
164
120
 
165
121
  // --- Suggested action — accent-coloured whole control ---
166
122
  &.suggested-action {
@@ -0,0 +1,90 @@
1
+ // _switch.scss — the <adw-switch> control: a track, a hidden checkbox and a
2
+ // sliding knob. UNSCOPED, which is the whole point of the partial.
3
+ //
4
+ // WHY IT IS ITS OWN FILE. These rules used to live inside `_switch_row.scss`,
5
+ // nested under `adw-switch-row { … }` — so `.adw-switch` did not exist anywhere
6
+ // else, and the moment a second widget needed a toggle it could not use it.
7
+ // `_expander_row.scss` therefore carried a character-for-character copy of the
8
+ // whole block (same 44×24 box, same hidden input, same 20px knob, same
9
+ // `translateX(20px)`, same focus ring) under a different class name. Two copies
10
+ // of a control is how a hover state gets fixed in one of them.
11
+ //
12
+ // FIDELITY, RECORDED RATHER THAN "FIXED": the 44×24 track with the 20px knob is
13
+ // `refs/adwaita-web/adwaita-web/scss/_switch.scss`'s geometry, NOT libadwaita's.
14
+ // libadwaita draws `switch` as a 3px-padded trough around a 20px slider with
15
+ // `border-radius: 14px` (refs/libadwaita/src/stylesheet/widgets/_switch.scss:3-4,
16
+ // :24-26) — about 26px tall, not 24, and correspondingly narrower. What ships
17
+ // here is the vendored web port's box, unchanged by the extraction; changing the
18
+ // geometry is a visual decision for a separate change, and citing libadwaita for
19
+ // numbers that came from somewhere else would be the misreading the conformance
20
+ // header warns about.
21
+ //
22
+ // Reference: refs/adwaita-web/adwaita-web/scss/_switch.scss (the geometry that ships)
23
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_switch.scss:3-4,20-26 (the geometry that does not, + the disabled treatment)
24
+ // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
25
+ // Copyright (c) 2025 csm (adwaita-web). MIT License.
26
+ // Modifications: Adapted for @gjsify/adwaita-web Web Components; lifted out of
27
+ // `adw-switch-row {}` so <adw-switch> is usable anywhere.
28
+
29
+ .adw-switch {
30
+ position: relative;
31
+ display: inline-block;
32
+ width: 44px;
33
+ height: 24px;
34
+ flex-shrink: 0;
35
+
36
+ // The real control: focusable and keyboard-toggleable, but never painted —
37
+ // the slider below is what the user sees and clicks.
38
+ input {
39
+ opacity: 0;
40
+ width: 0;
41
+ height: 0;
42
+ position: absolute;
43
+ }
44
+ }
45
+
46
+ .adw-switch-slider {
47
+ position: absolute;
48
+ cursor: pointer;
49
+ inset: 0;
50
+ background-color: var(--switch-off-bg);
51
+ border-radius: 12px;
52
+ transition: background-color 0.15s ease-out;
53
+
54
+ &::before {
55
+ content: "";
56
+ position: absolute;
57
+ height: 20px;
58
+ width: 20px;
59
+ left: 2px;
60
+ bottom: 2px;
61
+ background-color: var(--switch-knob-bg);
62
+ border-radius: 50%;
63
+ transition: transform 0.15s ease-out;
64
+ box-shadow: 0 1px 2px rgb(0 0 0 / 20%);
65
+ }
66
+ }
67
+
68
+ .adw-switch input:checked + .adw-switch-slider {
69
+ background-color: var(--accent-bg-color);
70
+
71
+ &::before {
72
+ transform: translateX(20px);
73
+ }
74
+ }
75
+
76
+ .adw-switch input:focus-visible + .adw-switch-slider {
77
+ outline: 2px solid var(--accent-color);
78
+ outline-offset: 2px;
79
+ }
80
+
81
+ // libadwaita dims the whole widget (`filter: Opacity(var(--disabled-opacity))`,
82
+ // _switch.scss:20-22). This package has no `--disabled-opacity` token, so the
83
+ // existing `--dim-opacity` stands in rather than a fourth invented colour.
84
+ .adw-switch.disabled {
85
+ opacity: var(--dim-opacity);
86
+
87
+ .adw-switch-slider {
88
+ cursor: not-allowed;
89
+ }
90
+ }
@@ -1,7 +1,11 @@
1
1
  // _switch_row.scss — adw-switch-row styling.
2
+ //
3
+ // The TOGGLE is not here: it is `<adw-switch>` and `scss/_switch.scss`. It used
4
+ // to be, nested under `adw-switch-row {`, which is exactly why `.adw-switch` was
5
+ // unreachable from anywhere else and `_expander_row.scss` grew a
6
+ // character-for-character copy of it.
7
+ //
2
8
  // Reference: refs/adwaita-web/adwaita-web/scss/_switch_row.scss
3
- // Reference: refs/adwaita-web/adwaita-web/scss/_switch.scss
4
- // Reference: refs/libadwaita/src/stylesheet/widgets/_switch.scss
5
9
  // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
6
10
  // Copyright (c) 2025 csm (adwaita-web). MIT License.
7
11
  // Modifications: Adapted for @gjsify/adwaita-web Web Components.
@@ -11,54 +15,4 @@ adw-switch-row {
11
15
  font-size: var(--font-size-base);
12
16
  color: var(--card-fg-color);
13
17
  }
14
-
15
- .adw-switch {
16
- position: relative;
17
- display: inline-block;
18
- width: 44px;
19
- height: 24px;
20
- flex-shrink: 0;
21
-
22
- input {
23
- opacity: 0;
24
- width: 0;
25
- height: 0;
26
- position: absolute;
27
- }
28
- }
29
-
30
- .adw-switch-slider {
31
- position: absolute;
32
- cursor: pointer;
33
- inset: 0;
34
- background-color: var(--switch-off-bg);
35
- border-radius: 12px;
36
- transition: background-color 0.15s ease-out;
37
-
38
- &::before {
39
- content: "";
40
- position: absolute;
41
- height: 20px;
42
- width: 20px;
43
- left: 2px;
44
- bottom: 2px;
45
- background-color: var(--switch-knob-bg);
46
- border-radius: 50%;
47
- transition: transform 0.15s ease-out;
48
- box-shadow: 0 1px 2px rgb(0 0 0 / 20%);
49
- }
50
- }
51
-
52
- .adw-switch input:checked + .adw-switch-slider {
53
- background-color: var(--accent-bg-color);
54
-
55
- &::before {
56
- transform: translateX(20px);
57
- }
58
- }
59
-
60
- .adw-switch input:focus-visible + .adw-switch-slider {
61
- outline: 2px solid var(--accent-color);
62
- outline-offset: 2px;
63
- }
64
18
  }
@@ -127,7 +127,67 @@ adw-tab-view {
127
127
  min-width: 0;
128
128
  }
129
129
 
130
+ // --- Icon + indicator slots (AdwTab update_icons) ---
131
+ // Both are mask-image spans carrying `adw-icon adw-icon--<name>`; the element
132
+ // toggles `hidden` from `tabIconState`, whose rules decide which of the two
133
+ // shows — on a pinned tab the indicator REPLACES the icon.
134
+ // Reference: refs/libadwaita/src/adw-tab.c (update_icons, :171-198)
135
+ .adw-tab-icon,
136
+ .adw-tab-indicator {
137
+ flex-shrink: 0;
138
+ width: 16px;
139
+ height: 16px;
140
+
141
+ &[hidden] {
142
+ display: none;
143
+ }
144
+ }
145
+
146
+ // `AdwTabPage:loading` swaps the icon image for a spinner in the same slot
147
+ // (adw-tab.c:178-183) — the arc geometry and the keyframes are adw-spinner's,
148
+ // not a second copy of them.
149
+ .adw-tab-icon.loading {
150
+ background: none;
151
+ mask-image: none;
152
+ border: 2px solid rgba(127, 127, 127, 0.25);
153
+ border-top-color: currentColor;
154
+ border-radius: 50%;
155
+ animation: adw-spinner-spin 0.8s linear infinite;
156
+
157
+ @media (prefers-reduced-motion: reduce) {
158
+ animation: none;
159
+ }
160
+ }
161
+
162
+ // A pinned tab is a single-glyph chip: libadwaita hides both the title and the
163
+ // close button at construction (refs/libadwaita/src/adw-tab.c:645-650). The
164
+ // close button is gated in JS by `tabCloseVisible`, which carries the same rule.
165
+ .adw-tab.pinned {
166
+ padding: 0 var(--spacing-xs);
167
+
168
+ .adw-tab-title {
169
+ display: none;
170
+ }
171
+ }
172
+
173
+ // `AdwTabPage:needs-attention` — the accent underline libadwaita animates in
174
+ // (refs/libadwaita/src/adw-tab.c update_needs_attention).
175
+ .adw-tab.needs-attention::after {
176
+ content: '';
177
+ position: absolute;
178
+ bottom: 2px;
179
+ left: 50%;
180
+ width: 12px;
181
+ height: 2px;
182
+ transform: translateX(-50%);
183
+ border-radius: 1px;
184
+ background-color: var(--accent-bg-color);
185
+ }
186
+
130
187
  // --- Close affordance (CSS-drawn "×", no symbolic icon ships) ---
188
+ // Presence is decided in JS by `tabCloseVisible` — `(hovering && fullyVisible)
189
+ // || selected || dragging`, and never on a pinned tab (adw-tab.c:124, :645-650)
190
+ // — which is why the `[hidden]` rule below is load-bearing rather than cosmetic.
131
191
  .adw-tab-close {
132
192
  box-sizing: border-box;
133
193
  flex-shrink: 0;
@@ -146,6 +206,10 @@ adw-tab-view {
146
206
  background-color 150ms ease-in-out,
147
207
  opacity 150ms ease-in-out;
148
208
 
209
+ &[hidden] {
210
+ display: none;
211
+ }
212
+
149
213
  &:hover {
150
214
  opacity: 1;
151
215
  background-color: var(--button-hover-color);
package/scss/_theme.scss CHANGED
@@ -31,6 +31,16 @@
31
31
  --entry-border-hover-color: rgba(255, 255, 255, 0.26);
32
32
  --destructive-bg-color: #c01c28;
33
33
  --destructive-fg-color: #ffffff;
34
+ // Semantic states — libadwaita's dark overrides (_colors.scss:83-92): the
35
+ // backgrounds darken (green_5 / a hand-picked amber / red_4) and the
36
+ // standalone colour LIGHTENS instead of darkening, so it stays readable on a
37
+ // dark surface. Upstream does not re-declare the `*-fg-color`s here either.
38
+ --success-bg-color: #26a269;
39
+ --success-color: oklab(from var(--success-bg-color) max(l, 0.85) a b);
40
+ --warning-bg-color: #cd9309;
41
+ --warning-color: oklab(from var(--warning-bg-color) max(l, 0.85) a b);
42
+ --error-bg-color: #c01c28;
43
+ --error-color: oklab(from var(--error-bg-color) max(l, 0.85) a b);
34
44
  --switch-off-bg: rgba(255, 255, 255, 0.2);
35
45
  --switch-knob-bg: #deddda;
36
46
  // The active toggle is a raised near-white chip in both themes, so its text
@@ -11,6 +11,8 @@ adw-toolbar-view {
11
11
  min-height: 0;
12
12
  min-width: 0;
13
13
  flex: 1 1 auto;
14
+ // Positioning context for the extend-content-to-*-edge overlays below.
15
+ position: relative;
14
16
 
15
17
  .adw-toolbar-view-top,
16
18
  .adw-toolbar-view-bottom {
@@ -28,4 +30,76 @@ adw-toolbar-view {
28
30
  flex-direction: column;
29
31
  background-color: var(--window-bg-color);
30
32
  }
33
+
34
+ // top-bar-style / bottom-bar-style: an opaque background plus a persistent
35
+ // shadow, which `.border` swaps for a hairline (adw-toolbar-view.c:1011-1024,
36
+ // _toolbars.scss `> .top-bar.raised`).
37
+ .adw-toolbar-view-top.raised,
38
+ .adw-toolbar-view-bottom.raised {
39
+ background-color: var(--headerbar-bg-color);
40
+ color: var(--headerbar-fg-color);
41
+ }
42
+
43
+ .adw-toolbar-view-top.raised {
44
+ box-shadow:
45
+ 0 1px var(--headerbar-shade-color),
46
+ 0 2px 4px var(--headerbar-shade-color);
47
+
48
+ &.border {
49
+ box-shadow: 0 1px var(--headerbar-shade-color);
50
+ }
51
+ }
52
+
53
+ .adw-toolbar-view-bottom.raised {
54
+ box-shadow:
55
+ 0 -1px var(--headerbar-shade-color),
56
+ 0 -2px 4px var(--headerbar-shade-color);
57
+
58
+ &.border {
59
+ box-shadow: 0 -1px var(--headerbar-shade-color);
60
+ }
61
+ }
62
+
63
+ // The scroll fade under a FLAT bar. libadwaita paints it on the scrolled
64
+ // window; the browser equivalent is a non-interactive gradient stuck to the
65
+ // scrollport edge, taking no space of its own — a NEGATIVE margin equal to its
66
+ // height (_toolbars.scss :342-343, _scrolling.scss :150-157).
67
+ &.undershoot-top .adw-toolbar-view-content::before,
68
+ &.undershoot-bottom .adw-toolbar-view-content::after {
69
+ content: '';
70
+ position: sticky;
71
+ height: 6px;
72
+ flex-shrink: 0;
73
+ pointer-events: none;
74
+ }
75
+
76
+ &.undershoot-top .adw-toolbar-view-content::before {
77
+ top: 0;
78
+ margin-bottom: -6px;
79
+ background: linear-gradient(to bottom, var(--headerbar-shade-color), transparent);
80
+ }
81
+
82
+ &.undershoot-bottom .adw-toolbar-view-content::after {
83
+ bottom: 0;
84
+ margin-top: -6px;
85
+ background: linear-gradient(to top, var(--headerbar-shade-color), transparent);
86
+ }
87
+ }
88
+
89
+ // extend-content-to-*-edge: the content spans the full height and the bar is
90
+ // drawn OVER it, which is `content_offset = 0` / `content_height = height` in
91
+ // adw_toolbar_view_size_allocate (adw-toolbar-view.c:390-397).
92
+ adw-toolbar-view[extend-content-to-top-edge] > .adw-toolbar-view-top,
93
+ adw-toolbar-view[extend-content-to-bottom-edge] > .adw-toolbar-view-bottom {
94
+ position: absolute;
95
+ left: 0;
96
+ right: 0;
97
+ }
98
+
99
+ adw-toolbar-view[extend-content-to-top-edge] > .adw-toolbar-view-top {
100
+ top: 0;
101
+ }
102
+
103
+ adw-toolbar-view[extend-content-to-bottom-edge] > .adw-toolbar-view-bottom {
104
+ bottom: 0;
31
105
  }
@@ -60,6 +60,23 @@
60
60
  --destructive-bg-color: #e01b24;
61
61
  --destructive-fg-color: #ffffff;
62
62
 
63
+ // Semantic states. `.error` / `.warning` / `.success` (see _labels.scss) do
64
+ // not just recolour text — they REBIND the three accent tokens to these, so
65
+ // anything accent-coloured inside them follows. Values are libadwaita's
66
+ // (_colors.scss:16-29): red_3 / yellow_5 / green_4 from _palette.scss:106-121.
67
+ // The standalone `*-color` is upstream's own relative-colour derivation of the
68
+ // background, kept as an expression rather than resolved to a hex so it tracks
69
+ // a re-themed `*-bg-color`.
70
+ --success-bg-color: #2ec27e;
71
+ --success-fg-color: #ffffff;
72
+ --success-color: oklab(from var(--success-bg-color) min(l, 0.5) a b);
73
+ --warning-bg-color: #e5a50a;
74
+ --warning-fg-color: rgba(0, 0, 0, 0.8);
75
+ --warning-color: oklab(from var(--warning-bg-color) min(l, 0.5) a b);
76
+ --error-bg-color: #e01b24;
77
+ --error-fg-color: #ffffff;
78
+ --error-color: oklab(from var(--error-bg-color) min(l, 0.5) a b);
79
+
63
80
  // Switch
64
81
  --switch-off-bg: rgba(0, 0, 0, 0.2);
65
82
  --switch-knob-bg: #ffffff;
@@ -82,4 +99,21 @@
82
99
  --font-size-small: 9pt;
83
100
  --font-size-heading: 12pt;
84
101
  --dim-opacity: 0.55;
102
+
103
+ // Document + monospace families, behind `.document` / `.monospace`
104
+ // (_labels.scss:75-84). In GTK these four are written into `:root` at RUNTIME
105
+ // by AdwStyleManager from the desktop's font settings
106
+ // (adw-style-manager.c:169-218), defaulting to `Sans 10` / `Monospace 10`
107
+ // (:50-56). A browser has no style manager, so they are ordinary tokens here
108
+ // — same names, so re-theming goes through the documented contract. The
109
+ // monospace stack is the one `_data_grid.scss` used to inline; it has ONE home
110
+ // now, and Adwaita Mono heads it because `@gjsify/adwaita-fonts` ships it.
111
+ // `'Cantarell'` is dropped from that stack on the way here: Cantarell is
112
+ // GNOME's PROPORTIONAL UI font, so a monospace fallback chain that reaches it
113
+ // second lands on a font whose figures do not line up — the exact property
114
+ // `.monospace` exists for.
115
+ --document-font-family: var(--font-family);
116
+ --document-font-size: var(--font-size-base);
117
+ --monospace-font-family: 'Adwaita Mono', ui-monospace, 'SF Mono', 'Menlo', monospace;
118
+ --monospace-font-size: var(--font-size-base);
85
119
  }