@gjsify/adwaita-web 0.31.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 @@
1
+ export declare const AdwTabViewConformanceTest: () => Promise<void>;
@@ -0,0 +1 @@
1
+ export declare const AdwViewStackTest: () => Promise<void>;
@@ -0,0 +1 @@
1
+ export declare const AdwViewSwitcherTest: () => Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/adwaita-web",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "Adwaita/Libadwaita web components for browser targets",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -41,14 +41,14 @@
41
41
  "@codemirror/language": "^6.12.4",
42
42
  "@codemirror/state": "^6.7.0",
43
43
  "@codemirror/view": "^6.43.4",
44
- "@gjsify/adwaita-core": "^0.31.0",
45
- "@gjsify/adwaita-fonts": "^0.31.0",
46
- "@gjsify/adwaita-icons": "^0.31.0",
44
+ "@gjsify/adwaita-core": "^0.32.0",
45
+ "@gjsify/adwaita-fonts": "^0.32.0",
46
+ "@gjsify/adwaita-icons": "^0.32.0",
47
47
  "@lezer/highlight": "^1.2.3"
48
48
  },
49
49
  "devDependencies": {
50
- "@gjsify/cli": "^0.31.0",
51
- "@gjsify/unit": "^0.31.0",
50
+ "@gjsify/cli": "^0.32.0",
51
+ "@gjsify/unit": "^0.32.0",
52
52
  "sass": "^1.101.0",
53
53
  "typescript": "^6.0.3"
54
54
  },
package/scss/_banner.scss CHANGED
@@ -42,5 +42,18 @@ adw-banner {
42
42
  &:hover {
43
43
  background: var(--button-hover-color);
44
44
  }
45
+
46
+ // `button-style` (Since 1.7). ADW_BANNER_BUTTON_SUGGESTED adds
47
+ // `.suggested-action` to the banner button (adw-banner.c:769), which is the
48
+ // shared accent appearance — the same declaration `.adw-button.suggested-action`
49
+ // carries, restated here because the banner button is not an `.adw-button`.
50
+ &.suggested-action {
51
+ background: var(--accent-bg-color);
52
+ color: var(--accent-fg-color);
53
+
54
+ &:hover {
55
+ background: var(--accent-color);
56
+ }
57
+ }
45
58
  }
46
59
  }
@@ -80,6 +80,10 @@ adw-bottom-sheet {
80
80
  // --- Drag handle (overlaid pill at the top of the sheet) ---
81
81
  // libadwaita: > drag-handle { min-width 54px; min-height 6px; margin 15px;
82
82
  // border-radius 99px; background currentColor @ 25% }.
83
+ // It is built with can_focus = FALSE and can_target = FALSE
84
+ // (adw-bottom-sheet.c:1197-1198) — a decorative pill, not a button;
85
+ // `pointer-events: none` is can_target in CSS. The `cursor: pointer` + focus
86
+ // ring that used to sit here belonged to a close button this widget never had.
83
87
  .adw-bottom-sheet-drag-handle {
84
88
  flex-shrink: 0;
85
89
  box-sizing: border-box;
@@ -89,12 +93,7 @@ adw-bottom-sheet {
89
93
  margin: 15px auto;
90
94
  border-radius: 99px;
91
95
  background-color: color-mix(in srgb, currentColor 25%, transparent);
92
- cursor: pointer;
93
-
94
- &:focus-visible {
95
- outline: 2px solid var(--accent-color);
96
- outline-offset: 4px;
97
- }
96
+ pointer-events: none;
98
97
  }
99
98
 
100
99
  .adw-bottom-sheet-sheet-body {
package/scss/_button.scss CHANGED
@@ -114,32 +114,9 @@ adw-button {
114
114
  }
115
115
  }
116
116
 
117
- // Symbolic icon rendered via a CSS mask so `currentColor` drives the fill,
118
- // keeping it theme-aware (same technique as the combo-row dropdown arrow).
119
- .adw-icon {
120
- display: inline-block;
121
- width: 16px;
122
- height: 16px;
123
- flex-shrink: 0;
124
- background-color: currentColor;
125
- mask-size: 16px;
126
- mask-repeat: no-repeat;
127
- mask-position: center;
128
- -webkit-mask-size: 16px;
129
- -webkit-mask-repeat: no-repeat;
130
- -webkit-mask-position: center;
131
-
132
- // `display: inline-block` (author CSS) otherwise beats the UA `[hidden]`
133
- // rule, so a hidden icon (e.g. an avatar's fallback icon while initials
134
- // show) would still render as a solid maskless square. Honor `hidden`.
135
- &[hidden] {
136
- display: none;
137
- }
138
- }
139
-
140
- // The per-name `.adw-icon--<name>` mask classes are generated into
141
- // scss/_icons.generated.scss by scripts/build-scss.mjs (one entry per icon in
142
- // its ICONS map), so adding an icon is a single map edit.
117
+ // The symbolic icon (`.adw-icon`) used to be declared here, because the first
118
+ // widget that needed one was the button. It is `scss/_icon.scss` now — every
119
+ // other widget needs one too, and `<adw-icon>` is an element.
143
120
 
144
121
  // Linked group — adjacent buttons share edges (segmented control).
145
122
  .adw-linked {
@@ -7,6 +7,34 @@
7
7
  // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
8
8
  // Modifications: Adapted for @gjsify/adwaita-web Web Components.
9
9
 
10
+ // The class <adw-button-content> stamps on the button hosting it
11
+ // (adw-button-content.c:115), removed again on unroot (:126).
12
+ //
13
+ // libadwaita: `button.image-text-button { padding-left: 9px; padding-right: 9px }`
14
+ // (_buttons.scss:77-80) — against the 17px a plain `.text-button` gets (:72-75).
15
+ // This rule lived in NEITHER renderer, so every icon+label button was drawn with
16
+ // the wrong horizontal padding.
17
+ //
18
+ // Only the PADDING half of that block applies here. The same selector also
19
+ // declares `> box, > box > box { border-spacing: 4px }` (:82-84), and neither
20
+ // matches: the node tree is `button > buttoncontent > box` (:47-52), so the
21
+ // button's direct child is the `buttoncontent`, not a box. The icon↔label gap
22
+ // stays the 6px `buttoncontent > box` gives it (:626-628), which is the `gap`
23
+ // below. It lives in this file rather than in `_button.scss` because the class
24
+ // belongs to this widget, and `.adw-button.image-text-button` beats `.adw-button`
25
+ // on specificity regardless of order.
26
+ .adw-button.image-text-button {
27
+ padding-left: 9px;
28
+ padding-right: 9px;
29
+ }
30
+
31
+ // Inside a split button the class sits on the `splitbutton` node instead, and a
32
+ // DIFFERENT block wins: `splitbutton.image-text-button > button` (:499-502).
33
+ .adw-split-button.image-text-button > .adw-split-button-action {
34
+ padding-left: 9px;
35
+ padding-right: 9px;
36
+ }
37
+
10
38
  adw-button-content {
11
39
  display: inline-flex;
12
40
  align-items: center;
@@ -0,0 +1,228 @@
1
+ // _checks.scss — <adw-checkbox> AND <adw-radio>, in ONE partial.
2
+ //
3
+ // WHY ONE FILE FOR TWO ELEMENTS. `refs/libadwaita/src/stylesheet/widgets/
4
+ // _checks.scss` merges them deliberately: everything but the corner radius and
5
+ // the glyph is a shared `check, radio { … }` block (:20-65), and the
6
+ // indeterminate dash is re-declared for BOTH at the end (:79-81). There is no
7
+ // `_radio.scss` upstream to mirror. `refs/adwaita-web` does split them into
8
+ // `_checkbox.scss` + `_radio.scss`, and the split is exactly where it drifted:
9
+ // its two indicators grew different sizes, different border treatments and
10
+ // different selection-mode rules, and only one of them has a hover state.
11
+ //
12
+ // TWO PLACES THE VENDORED WEB PORT DISAGREES WITH LIBADWAITA. libadwaita is
13
+ // followed in both:
14
+ //
15
+ // 1. INDETERMINATE. `refs/adwaita-web/adwaita-web/scss/_checkbox.scss` has no
16
+ // indeterminate state at all — no dash, no third glyph, nothing. libadwaita
17
+ // paints it with the same accent fill as checked (:52-60) and its own dash
18
+ // glyph (:79-81). Ported.
19
+ // 2. THE CHECKED RADIO. `refs/adwaita-web/adwaita-web/scss/_radio.scss:22-33`
20
+ // colours only the BORDER and the dot with `--accent-color`, leaving the
21
+ // indicator's background as the view colour. libadwaita FILLS the whole
22
+ // control with `--accent-bg-color` and draws the bullet in
23
+ // `--accent-fg-color` (:54-55) — the same treatment the checkbox gets, which
24
+ // is the point of the shared block. Ported.
25
+ //
26
+ // THE GLYPHS ARE LIBADWAITA'S OWN ASSETS. GTK draws them with
27
+ // `-gtk-icon-source: -gtk-recolor(url("assets/check.svg"))` (:70, :76, :80),
28
+ // which has no CSS spelling. The path data below is copied from
29
+ // `refs/libadwaita/src/stylesheet/assets/{check,bullet,dash}.svg` and painted as
30
+ // a mask filled with `currentColor` — the same technique `_icon.scss` already
31
+ // uses, and what makes `-gtk-recolor` work here: the shared block sets
32
+ // `color: var(--accent-fg-color)` on a checked indicator, so the glyph follows.
33
+ // `bullet.svg` carries a `transform="translate(-381 -339)"` on a path whose
34
+ // commands after the first are all relative, so the translation is folded into
35
+ // the absolute `M` (388,342 → 7,3) and nothing else changes.
36
+ //
37
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_checks.scss (all of it)
38
+ // Reference: refs/libadwaita/src/stylesheet/assets/{check,bullet,dash}.svg (the three glyphs)
39
+ // Reference: refs/libadwaita/src/stylesheet/_colors.scss:280-286 (the trough colours)
40
+ // Reference: refs/adwaita-web/adwaita-web/scss/{_checkbox,_radio}.scss (the vendored port's split, NOT followed — see above)
41
+ // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
42
+ // Copyright (c) 2025 csm (adwaita-web). MIT License.
43
+ // Modifications: Implemented as Web Components for @gjsify/adwaita-web; the GTK
44
+ // icon sources are re-expressed as CSS masks.
45
+
46
+ // assets/check.svg
47
+ $check-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14'%3E%3Cpath fill='black' d='m 12.599609,2.1992188 a 1,1 0 0 0 -1.40039,0.2011718 L 5.890625,9.4765625 2.7070313,6.2929687 a 1,1 0 0 0 -1.4140626,0 1,1 0 0 0 0,1.4140625 l 4,3.9999998 A 1.0001,1.0001 0 0 0 6.8007812,11.599609 L 12.800781,3.5996094 A 1,1 0 0 0 12.599609,2.1992188 Z'/%3E%3C/svg%3E");
48
+ // assets/bullet.svg
49
+ $bullet-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14'%3E%3Cpath fill='black' d='M 7 3 c -2.207 0 -4 1.793 -4 4 s 1.793 4 4 4 c 2.208 0 4 -1.793 4 -4 s -1.792 -4 -4 -4 z'/%3E%3C/svg%3E");
50
+ // assets/dash.svg
51
+ $dash-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14'%3E%3Cpath fill='black' d='M 3 5 A 2 2 0 0 0 1 7 A 2 2 0 0 0 3 9 L 11 9 A 2 2 0 0 0 13 7 A 2 2 0 0 0 11 5 Z'/%3E%3C/svg%3E");
52
+
53
+ // `checkbutton { … }` (:3-18) — the host is the button, not the indicator.
54
+ adw-checkbox,
55
+ adw-radio {
56
+ position: relative;
57
+ display: inline-flex;
58
+ align-items: center;
59
+ gap: 4px; // border-spacing: 4px (:4)
60
+ padding: 3px; // (:6)
61
+ border-radius: 9px; // $check_radius + 3px (:5)
62
+ cursor: pointer;
63
+ user-select: none;
64
+
65
+ // The real control: focusable and keyboard-operable, never painted. The
66
+ // indicator below is what the user sees; the host handles the pointer.
67
+ .adw-check-input {
68
+ position: absolute;
69
+ width: 0;
70
+ height: 0;
71
+ margin: 0;
72
+ opacity: 0;
73
+ }
74
+
75
+ // `check, radio { … }` (:20-31), shared by both elements.
76
+ .adw-check-indicator {
77
+ // GTK sizes the CONTENT box (`min-width`/`min-height: 14px`, :22-23) and
78
+ // grows the drawn control with `padding: 3px` (:26), i.e. 20x20. Opting out
79
+ // of the ADR-0010 descendant border-box pin keeps that arithmetic — and
80
+ // keeps `checkbutton.selection-mode`'s one-line `padding: 7px` (:87)
81
+ // working exactly as it does upstream instead of needing a second number.
82
+ box-sizing: content-box;
83
+ width: 14px;
84
+ height: 14px;
85
+ padding: 3px;
86
+ flex-shrink: 0;
87
+ box-shadow: inset 0 0 0 2px color-mix(in srgb, currentColor 15%, transparent); // $trough_color
88
+ transition:
89
+ background 200ms ease-out,
90
+ box-shadow 200ms ease-out;
91
+
92
+ @media (prefers-contrast: more) {
93
+ // $trough_color_hc (_colors.scss:284) stands in for $border_color: this
94
+ // package defines no `--border-opacity`, and the two are the same 30%
95
+ // mix of currentColor in the light theme.
96
+ box-shadow: inset 0 0 0 2px color-mix(in srgb, currentColor 30%, transparent);
97
+ }
98
+
99
+ // The glyph layer. No mask until a state supplies one, so an unchecked
100
+ // control paints nothing here.
101
+ &::after {
102
+ content: '';
103
+ display: block;
104
+ width: 100%;
105
+ height: 100%;
106
+ background-color: currentColor;
107
+ mask-repeat: no-repeat;
108
+ mask-position: center;
109
+ mask-size: 14px; // -gtk-icon-size: 14px (:25)
110
+ -webkit-mask-repeat: no-repeat;
111
+ -webkit-mask-position: center;
112
+ -webkit-mask-size: 14px;
113
+ }
114
+ }
115
+
116
+ // `&:not(:checked):not(:indeterminate) { &:hover / &:active }` (:33-50).
117
+ // Hover and active live on the HOST here — the indicator is 20px inside a
118
+ // control whose label is part of the target, exactly as `checkbutton` is.
119
+ &:not([checked]):not([indeterminate]):not([disabled]) {
120
+ &:hover .adw-check-indicator {
121
+ box-shadow: inset 0 0 0 2px color-mix(in srgb, currentColor 20%, transparent); // $trough_hover_color
122
+
123
+ @media (prefers-contrast: more) {
124
+ box-shadow: inset 0 0 0 2px color-mix(in srgb, currentColor 60%, transparent);
125
+ }
126
+ }
127
+
128
+ &:active .adw-check-indicator {
129
+ background-color: color-mix(in srgb, currentColor 25%, transparent); // $trough_active_color
130
+ box-shadow: none;
131
+
132
+ @media (prefers-contrast: more) {
133
+ background-color: color-mix(in srgb, currentColor 60%, transparent);
134
+ }
135
+ }
136
+ }
137
+
138
+ // `&:checked, &:indeterminate { … }` (:52-60) — ONE block for both states, so
139
+ // they differ only in the glyph.
140
+ &[checked] .adw-check-indicator,
141
+ &[indeterminate] .adw-check-indicator {
142
+ background-color: var(--accent-bg-color);
143
+ color: var(--accent-fg-color);
144
+ box-shadow: none;
145
+ }
146
+
147
+ // GTK's `background-image: image(<colour>)` (:58-59) is a flat fill; a
148
+ // two-stop gradient of one colour is its CSS spelling, as `_button_row.scss`
149
+ // already does.
150
+ &[checked]:not([disabled]),
151
+ &[indeterminate]:not([disabled]) {
152
+ &:hover .adw-check-indicator {
153
+ background-image: linear-gradient(
154
+ color-mix(in srgb, currentColor 10%, transparent),
155
+ color-mix(in srgb, currentColor 10%, transparent)
156
+ );
157
+ }
158
+
159
+ &:active .adw-check-indicator {
160
+ background-image: linear-gradient(rgb(0 0 6 / 20%), rgb(0 0 6 / 20%));
161
+ }
162
+ }
163
+
164
+ // `&:disabled { filter: Opacity(var(--disabled-opacity)) }` (:62-64). This
165
+ // package defines no `--disabled-opacity`, so `--dim-opacity` stands in — the
166
+ // same substitution `_switch.scss` documents.
167
+ &[disabled] {
168
+ cursor: not-allowed;
169
+ opacity: var(--dim-opacity);
170
+ }
171
+
172
+ // `@include focus-ring()` on `checkbutton` (:8). The ring follows the real
173
+ // control's focus, not the host's, so keyboard focus is what shows it.
174
+ .adw-check-input:focus-visible ~ .adw-check-indicator {
175
+ outline: 2px solid var(--accent-color);
176
+ outline-offset: 2px;
177
+ }
178
+ }
179
+
180
+ // `check { border-radius: $check_radius }` (:67-68)
181
+ adw-checkbox .adw-check-indicator {
182
+ border-radius: 6px;
183
+ }
184
+
185
+ // `radio { border-radius: 100% }` (:73-74)
186
+ adw-radio .adw-check-indicator {
187
+ border-radius: 100%;
188
+ }
189
+
190
+ // `check:checked` → check.svg (:70) / `radio:checked` → bullet.svg (:76)
191
+ adw-checkbox[checked] .adw-check-indicator::after {
192
+ mask-image: $check-glyph;
193
+ -webkit-mask-image: $check-glyph;
194
+ }
195
+
196
+ adw-radio[checked] .adw-check-indicator::after {
197
+ mask-image: $bullet-glyph;
198
+ -webkit-mask-image: $bullet-glyph;
199
+ }
200
+
201
+ // `check, radio { &:indeterminate { … dash.svg } }` (:79-81). Upstream this is a
202
+ // SEPARATE rule after both `:checked` blocks at equal specificity, so the dash
203
+ // wins over the check/bullet on a control that is both. Same order, same
204
+ // specificity, same outcome here — and the same precedence `resolveCheckState`
205
+ // in `@gjsify/adwaita-core` encodes for the a11y value.
206
+ adw-checkbox[indeterminate] .adw-check-indicator::after,
207
+ adw-radio[indeterminate] .adw-check-indicator::after {
208
+ mask-image: $dash-glyph;
209
+ -webkit-mask-image: $dash-glyph;
210
+ }
211
+
212
+ // `checkbutton.selection-mode { … }` (:83-95) — the big round check used in a
213
+ // selection-mode header bar.
214
+ adw-checkbox.selection-mode,
215
+ adw-radio.selection-mode {
216
+ border-radius: 100px;
217
+
218
+ .adw-check-indicator {
219
+ padding: 7px;
220
+ border-radius: 100px;
221
+ }
222
+
223
+ // `label { &:dir(ltr) { margin-right: 6px } &:dir(rtl) { margin-left: 6px } }`
224
+ // (:91-94) — one logical property covers both directions.
225
+ .adw-check-label {
226
+ margin-inline-end: 6px;
227
+ }
228
+ }
package/scss/_clamp.scss CHANGED
@@ -1,11 +1,17 @@
1
- // _clamp.scss — adw-clamp styling (max-width + centered).
1
+ // _clamp.scss — adw-clamp styling.
2
+ //
3
+ // The element itself is deliberately UNCAPPED and full-width: it is the box the
4
+ // tightening curve is evaluated against, so it has to keep reporting the
5
+ // AVAILABLE width. The cap and the centring live on the children, written by the
6
+ // element from `clampAllocate` (see src/elements/adw-clamp.ts) — an element that
7
+ // capped itself would feed its own capped width back into its ResizeObserver.
8
+ //
9
+ // Reference: refs/libadwaita/src/adw-clamp-layout.c (adw_clamp_layout_allocate)
2
10
  // Reference: refs/adwaita-web/adwaita-web/scss/_clamp.scss
3
- // Reference: refs/libadwaita (Adw.Clamp)
4
11
  // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
5
12
  // Modifications: Adapted for @gjsify/adwaita-web Web Components.
6
13
 
7
14
  adw-clamp {
8
15
  display: block;
9
16
  width: 100%;
10
- margin-inline: auto;
11
17
  }
@@ -8,9 +8,17 @@
8
8
  // real element (hover, hairline rules, activation) while columns stay aligned.
9
9
  // Reference: refs/libadwaita/src/stylesheet/_colors.scss (separator / card / dim tokens)
10
10
  // Reference: refs/libadwaita/src/stylesheet/widgets/_lists.scss (boxed-list density)
11
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_labels.scss:13-15,81-88 (.dimmed / .monospace / .numeric)
11
12
  // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
12
13
  // Modifications: Implemented for @gjsify/adwaita-web Web Components.
13
14
 
15
+ // `.dimmed` / `.monospace` / `.numeric`. This file used to declare
16
+ // `font-variant-numeric: tabular-nums` twice, inline a whole monospace font
17
+ // stack, and dim its header row with a raw `opacity: var(--dim-opacity)` — i.e.
18
+ // three private copies of utilities libadwaita publishes. It composes them now,
19
+ // the way upstream's own `_progress-bar.scss:17-21` composes the same two.
20
+ @use 'labels';
21
+
14
22
  .adw-data-grid {
15
23
  display: block;
16
24
  box-sizing: border-box;
@@ -68,13 +76,12 @@
68
76
  }
69
77
 
70
78
  // Tabular figures are the WHOLE POINT vs a boxed list — numbers line up.
71
- &.numeric {
72
- font-variant-numeric: tabular-nums;
73
- }
74
-
79
+ // `numeric` needs no rule at all: the cell carries the bare class, so
80
+ // libadwaita's own `.numeric` (_labels.scss:86-88) already applies.
81
+ // A mono cell is monospace AND tabular, so it composes both.
75
82
  &.mono {
76
- font-family: 'Adwaita Mono', 'Cantarell', ui-monospace, 'SF Mono', 'Menlo', monospace;
77
- font-variant-numeric: tabular-nums;
83
+ @extend .monospace;
84
+ @extend .numeric;
78
85
  }
79
86
  }
80
87
 
@@ -82,11 +89,12 @@
82
89
  // list-column headings), never sortable.
83
90
  .adw-data-grid-row.header {
84
91
  .adw-data-grid-cell {
92
+ @extend .dimmed;
93
+
85
94
  font-size: var(--font-size-small);
86
95
  font-weight: 700;
87
96
  text-transform: uppercase;
88
97
  letter-spacing: 0.04em;
89
- opacity: var(--dim-opacity);
90
98
  border-bottom: 1px solid var(--separator-color);
91
99
  }
92
100
  }
@@ -76,29 +76,18 @@
76
76
  opacity: 0.55;
77
77
  }
78
78
 
79
- // --- Popover list ---
80
- // The elevated surface below the button. Reproduces popover.menu > contents.
79
+ // The popover SURFACE is `<adw-popover>`'s (`_popover.scss`, the `[menu]`
80
+ // variant — a dropdown's popover is a `popover.menu`, _dropdowns.scss:22).
81
+ // What stays here is what libadwaita ALSO scopes to `dropdown`:
82
+ // - the extra 6px above the contents (`popover.menu { padding-top: 6px }`,
83
+ // _dropdowns.scss:23). GTK puts it on the popover node while the 6px inset
84
+ // sits on `> contents`; flattened onto one node they add, which is what
85
+ // the two-node original renders too.
86
+ // - the width tracking the button rather than libadwaita's flat `min-width`.
81
87
  .adw-drop-down-popover {
82
- position: absolute;
83
- top: calc(100% + 6px);
84
- left: 0;
85
- z-index: 10;
86
- display: flex;
87
- flex-direction: column;
88
+ padding-top: 12px;
88
89
  min-width: 100%;
89
90
  max-width: 320px;
90
- padding: var(--spacing-xs);
91
- border-radius: var(--card-radius);
92
- background-color: var(--popover-bg-color, var(--window-bg-color, #fff));
93
- color: var(--popover-fg-color, var(--window-fg-color));
94
- box-shadow:
95
- 0 0 0 1px rgba(0, 0, 0, 0.05),
96
- 0 1px 5px 1px rgba(0, 0, 0, 0.09),
97
- 0 2px 14px 3px rgba(0, 0, 0, 0.05);
98
-
99
- &[hidden] {
100
- display: none;
101
- }
102
91
  }
103
92
 
104
93
  // Search entry atop the popover (enable-search). It reuses the .adw-entry skin
@@ -115,44 +104,12 @@
115
104
  overflow-y: auto;
116
105
  }
117
106
 
118
- // An option row — a flat rounded row with the label and a trailing check on
119
- // the selected one; fills on hover/focus like a modelbutton.
107
+ // An option row is `.adw-popover-item` (`_popover.scss` — libadwaita's
108
+ // `modelbutton`). Only the trailing-check layout is a drop-down fact: the
109
+ // label and the check sit at opposite ends of the row.
120
110
  .adw-drop-down-item {
121
- box-sizing: border-box;
122
- display: flex;
123
- align-items: center;
124
111
  justify-content: space-between;
125
112
  gap: var(--spacing-s);
126
- width: 100%;
127
- min-height: 32px;
128
- margin: 0;
129
- padding: var(--spacing-xs) var(--spacing-s);
130
- border: none;
131
- border-radius: calc(var(--button-radius) - 2px);
132
- background-color: transparent;
133
- color: inherit;
134
- font-family: var(--font-family);
135
- font-size: var(--font-size-base);
136
- text-align: start;
137
- cursor: pointer;
138
- transition: background-color 0.1s ease;
139
-
140
- &:hover {
141
- background-color: var(--button-hover-color);
142
- }
143
-
144
- &:active {
145
- background-color: var(--button-active-color);
146
- }
147
-
148
- &:focus-visible {
149
- outline: 2px solid var(--accent-color);
150
- outline-offset: -2px;
151
- }
152
-
153
- &[hidden] {
154
- display: none;
155
- }
156
113
  }
157
114
 
158
115
  .adw-drop-down-item-label {
@@ -69,56 +69,11 @@ adw-expander-row {
69
69
  transform: rotate(180deg);
70
70
  }
71
71
 
72
- // The optional enable switch reuses the shared .adw-switch markup.
73
- .adw-expander-row-enable-switch {
74
- position: relative;
75
- display: inline-block;
76
- width: 44px;
77
- height: 24px;
78
- flex-shrink: 0;
79
-
80
- input {
81
- opacity: 0;
82
- width: 0;
83
- height: 0;
84
- position: absolute;
85
- }
86
-
87
- .adw-switch-slider {
88
- position: absolute;
89
- cursor: pointer;
90
- inset: 0;
91
- background-color: var(--switch-off-bg);
92
- border-radius: 12px;
93
- transition: background-color 0.15s ease-out;
94
-
95
- &::before {
96
- content: "";
97
- position: absolute;
98
- height: 20px;
99
- width: 20px;
100
- left: 2px;
101
- bottom: 2px;
102
- background-color: var(--switch-knob-bg);
103
- border-radius: 50%;
104
- transition: transform 0.15s ease-out;
105
- box-shadow: 0 1px 2px rgb(0 0 0 / 20%);
106
- }
107
- }
108
-
109
- input:checked + .adw-switch-slider {
110
- background-color: var(--accent-bg-color);
111
-
112
- &::before {
113
- transform: translateX(20px);
114
- }
115
- }
116
-
117
- input:focus-visible + .adw-switch-slider {
118
- outline: 2px solid var(--accent-color);
119
- outline-offset: 2px;
120
- }
121
- }
72
+ // The optional enable switch is `<adw-switch>` and needs no geometry of its
73
+ // own — `.adw-expander-row-enable-switch` is a query/override hook only. This
74
+ // block used to be a character-for-character copy of the switch row's toggle
75
+ // (44×24 box, hidden input, 20px knob, translateX(20px), focus ring), because
76
+ // `.adw-switch` was nested inside `adw-switch-row {` and unreachable from here.
122
77
 
123
78
  // Disclosed content — a nested listbox of rows, hidden until expanded. The
124
79
  // nested surface is slightly inset/recessed, the way libadwaita draws it.
@@ -0,0 +1,51 @@
1
+ // _icon.scss — the symbolic icon box behind <adw-icon>.
2
+ //
3
+ // A symbolic icon is rendered as a CSS mask rather than an <img> or inline SVG,
4
+ // so `currentColor` drives the fill and the glyph re-themes with whatever
5
+ // contains it. The per-name `.adw-icon--<name>` mask classes are GENERATED into
6
+ // scss/_icons.generated.scss by scripts/build-scss.mjs (one entry per icon in
7
+ // its ICONS map), so adding an icon is a single map edit.
8
+ //
9
+ // This block lived in `_button.scss` for as long as the button was the only
10
+ // widget that drew one. It is emitted BEFORE the widget partials so a context
11
+ // that sizes its own icons (`.adw-about-dialog-icon` at 96px, the split button's
12
+ // 14px arrows, the view switcher's 16px) still wins on ordinary specificity.
13
+ //
14
+ // Reference: refs/libadwaita/src/stylesheet/_common.scss:34-41 — `.normal-icons`
15
+ // / `.large-icons` set `-gtk-icon-size`. libadwaita has NO `_icon.scss`: there
16
+ // the icon is a GtkImage and its size is a widget property, not a rule.
17
+ // Reference: refs/adwaita-web/adwaita-web/scss/_icon.scss — the vendored web
18
+ // port's `.adw-icon` is an inline-flex holder around a real <svg>; this
19
+ // package masks instead, which is what keeps it colourable via currentColor.
20
+ // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
21
+ // Copyright (c) 2025 csm (adwaita-web). MIT License.
22
+ // Modifications: Adapted for @gjsify/adwaita-web Web Components (mask-based).
23
+
24
+ .adw-icon {
25
+ display: inline-block;
26
+ width: 16px;
27
+ height: 16px;
28
+ flex-shrink: 0;
29
+ background-color: currentColor;
30
+ mask-size: 16px;
31
+ mask-repeat: no-repeat;
32
+ mask-position: center;
33
+ -webkit-mask-size: 16px;
34
+ -webkit-mask-repeat: no-repeat;
35
+ -webkit-mask-position: center;
36
+
37
+ // `currentColor` IS the icon: the mask is painted with the inherited colour,
38
+ // so a suggested-action button's `--accent-fg-color` has to reach it. Since
39
+ // <adw-icon> is a custom element it is also in `$adw-components`, and the
40
+ // ADR-0010 boundary reset re-roots `color` on every entry there — which would
41
+ // otherwise repaint every icon in `--window-fg-color` regardless of its host.
42
+ // Class beats type selector, so this restores inheritance.
43
+ color: inherit;
44
+
45
+ // `display: inline-block` (author CSS) otherwise beats the UA `[hidden]`
46
+ // rule, so a hidden icon (e.g. an avatar's fallback icon while initials
47
+ // show) would still render as a solid maskless square. Honor `hidden`.
48
+ &[hidden] {
49
+ display: none;
50
+ }
51
+ }