@gjsify/adwaita-web 0.36.0 → 0.38.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 +504 -34
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/accent.d.ts +28 -0
- package/lib/types/adw-accent.spec.d.ts +2 -0
- 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 +3 -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 +18 -7
- 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/_theme.scss +20 -2
- package/scss/_variables.scss +34 -1
- package/scss/adwaita-skin.scss +12 -0
- package/src/accent.ts +74 -0
- package/src/adw-about-dialog.spec.ts +34 -49
- package/src/adw-accent.spec.ts +105 -0
- 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 +24 -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 +6 -0
- package/src/view-stack.spec.ts +23 -34
- package/src/view-switcher.spec.ts +56 -84
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
// _style_classes.scss — libadwaita's documented, WIDGET-INDEPENDENT style classes.
|
|
2
|
+
//
|
|
3
|
+
// THE GAP THIS CLOSES
|
|
4
|
+
//
|
|
5
|
+
// `refs/libadwaita/doc/style-classes.md` is the public contract an app author
|
|
6
|
+
// reads: put `.card` on a box, `.boxed-list` on a list, `.toolbar` on a bar,
|
|
7
|
+
// `.linked` around a button group. Twenty-one of those classes had NO rule in
|
|
8
|
+
// this package (#1049) — and two of them looked ported because their names
|
|
9
|
+
// appear in comments (`.osd`, `.linked`) while the code spells its own
|
|
10
|
+
// `.adw-linked`. A consumer following the upstream documentation got nothing,
|
|
11
|
+
// silently, which is the worst failure mode for a styling contract.
|
|
12
|
+
//
|
|
13
|
+
// Widget-scoped classes are NOT here — they live with the widget whose markup
|
|
14
|
+
// they modify (`.property` in `_action_row.scss`, `.compact` in
|
|
15
|
+
// `_status_page.scss`, `.devel` in `_headerbar.scss`, `.osd`'s button and
|
|
16
|
+
// progress-bar variants in theirs), because that is where their selector needs
|
|
17
|
+
// to see the widget's inner nodes. `scripts/check-adwaita-style-classes.mjs`
|
|
18
|
+
// holds the ledger of which class lives where and fails when one has no rule at
|
|
19
|
+
// all.
|
|
20
|
+
//
|
|
21
|
+
// Reference: refs/libadwaita/doc/style-classes.md (the documented surface)
|
|
22
|
+
// Reference: refs/libadwaita/src/stylesheet/_common.scss:25-28,43-60,90-104
|
|
23
|
+
// Reference: refs/libadwaita/src/stylesheet/widgets/_misc.scss:4-7,21-32,197-236
|
|
24
|
+
// Reference: refs/libadwaita/src/stylesheet/widgets/_views.scss:1-18
|
|
25
|
+
// Reference: refs/libadwaita/src/stylesheet/widgets/_lists.scss:520-600
|
|
26
|
+
// Reference: refs/libadwaita/src/stylesheet/widgets/_toolbars.scss:91-102
|
|
27
|
+
// Reference: refs/libadwaita/src/stylesheet/widgets/_linked.scss:1-45
|
|
28
|
+
// Reference: refs/libadwaita/src/stylesheet/widgets/_scrolling.scss:150-166
|
|
29
|
+
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
30
|
+
// Modifications: Adapted for @gjsify/adwaita-web — GTK node names (`row`,
|
|
31
|
+
// `list`, `button`) become the custom-element tags and `.adw-*` structure
|
|
32
|
+
// classes this package renders, and GTK-only drawing (`image()`,
|
|
33
|
+
// `-gtk-icon-shadow`, `border-spacing` on a box) becomes its CSS equivalent.
|
|
34
|
+
|
|
35
|
+
/************
|
|
36
|
+
* Surfaces *
|
|
37
|
+
************/
|
|
38
|
+
|
|
39
|
+
// _common.scss:25-28 — an opaque window-coloured background on any node.
|
|
40
|
+
.background {
|
|
41
|
+
background-color: var(--window-bg-color);
|
|
42
|
+
color: var(--window-fg-color);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// _views.scss:1-18 — the content-area surface. `:disabled` and `:selected` are
|
|
46
|
+
// GTK pseudo-classes with no DOM counterpart; `[disabled]`/`[aria-selected]`
|
|
47
|
+
// are how the same states are spelled here, and both are what our own widgets
|
|
48
|
+
// already set.
|
|
49
|
+
.view {
|
|
50
|
+
background-color: var(--view-bg-color);
|
|
51
|
+
color: var(--view-fg-color);
|
|
52
|
+
|
|
53
|
+
&:disabled,
|
|
54
|
+
&[disabled] {
|
|
55
|
+
color: color-mix(in srgb, var(--view-fg-color) var(--disabled-opacity), transparent);
|
|
56
|
+
background-color: color-mix(in srgb, var(--window-bg-color) 60%, var(--view-bg-color));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
&[aria-selected='true'] {
|
|
60
|
+
background-color: color-mix(in srgb, var(--accent-bg-color) 25%, transparent);
|
|
61
|
+
border-radius: var(--button-radius);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// _misc.scss:4-7 — the default border. `--border-color` is derived from
|
|
66
|
+
// `currentColor`, so this follows the foreground of whatever it is drawn on.
|
|
67
|
+
.frame {
|
|
68
|
+
border: 1px solid var(--border-color);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/*********
|
|
72
|
+
* Cards *
|
|
73
|
+
*********/
|
|
74
|
+
|
|
75
|
+
// _misc.scss:197-236. The ONE card recipe: `adw-card` and the preferences
|
|
76
|
+
// group's list box each carried their own copy of these five declarations
|
|
77
|
+
// before this placeholder existed.
|
|
78
|
+
%card {
|
|
79
|
+
background-color: var(--card-bg-color);
|
|
80
|
+
color: var(--card-fg-color);
|
|
81
|
+
border-radius: var(--card-radius);
|
|
82
|
+
box-shadow:
|
|
83
|
+
0 0 0 1px rgb(0 0 6 / 3%),
|
|
84
|
+
0 1px 3px 1px rgb(0 0 6 / 7%),
|
|
85
|
+
0 2px 6px 2px rgb(0 0 6 / 3%);
|
|
86
|
+
|
|
87
|
+
@media (prefers-contrast: more) {
|
|
88
|
+
box-shadow:
|
|
89
|
+
0 0 0 1px var(--border-color),
|
|
90
|
+
0 1px 3px 1px rgb(0 0 6 / 7%),
|
|
91
|
+
0 2px 6px 2px rgb(0 0 6 / 3%);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.card {
|
|
96
|
+
@extend %card;
|
|
97
|
+
|
|
98
|
+
// `.card.activatable` gets the hover/active states of an activatable row
|
|
99
|
+
// (:225-235). GTK's `background-image: image(…)` is a solid-colour layer over
|
|
100
|
+
// the background; a one-stop gradient is its CSS equivalent, and it composes
|
|
101
|
+
// with `background-color` the same way — so a re-themed card keeps its colour
|
|
102
|
+
// and only gains the wash.
|
|
103
|
+
&.activatable {
|
|
104
|
+
transition:
|
|
105
|
+
background-color 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94),
|
|
106
|
+
box-shadow 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
107
|
+
|
|
108
|
+
&:hover {
|
|
109
|
+
background-image: linear-gradient(
|
|
110
|
+
color-mix(in srgb, currentColor 3%, transparent),
|
|
111
|
+
color-mix(in srgb, currentColor 3%, transparent)
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
&:active {
|
|
116
|
+
background-image: linear-gradient(
|
|
117
|
+
color-mix(in srgb, currentColor 8%, transparent),
|
|
118
|
+
color-mix(in srgb, currentColor 8%, transparent)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// A card inside (or itself) an OSD surface loses its own elevation and reads
|
|
124
|
+
// as a translucent inset instead (:212-220).
|
|
125
|
+
.osd &,
|
|
126
|
+
&.osd {
|
|
127
|
+
background-color: color-mix(in srgb, currentColor 10%, transparent);
|
|
128
|
+
color: rgb(255 255 255 / 90%);
|
|
129
|
+
box-shadow: none;
|
|
130
|
+
|
|
131
|
+
@media (prefers-contrast: more) {
|
|
132
|
+
box-shadow: 0 0 0 1px var(--border-color);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/***************
|
|
138
|
+
* Boxed lists *
|
|
139
|
+
***************/
|
|
140
|
+
|
|
141
|
+
// _lists.scss:520-556. In GTK the row separators are drawn by the rows
|
|
142
|
+
// themselves and the list only supplies the card box plus the rounding of its
|
|
143
|
+
// two ends — which is exactly how this package's rows behave already
|
|
144
|
+
// (`adw-action-row` and friends draw their own `border-bottom` and drop it on
|
|
145
|
+
// `:last-child`), so the class is the box and the clip.
|
|
146
|
+
.boxed-list {
|
|
147
|
+
@extend %card;
|
|
148
|
+
|
|
149
|
+
display: flex;
|
|
150
|
+
flex-direction: column;
|
|
151
|
+
// The rounding of the first and last row is a CLIP here rather than per-row
|
|
152
|
+
// corner radii: a row is a custom element whose own background paints over
|
|
153
|
+
// the list's corners, and every row type would otherwise need the same four
|
|
154
|
+
// radii repeated.
|
|
155
|
+
overflow: hidden;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// :556-600 — same content, each row its own card. The list drops its box, and
|
|
159
|
+
// the rows carry it, spaced 12px apart.
|
|
160
|
+
.boxed-list-separate {
|
|
161
|
+
display: flex;
|
|
162
|
+
flex-direction: column;
|
|
163
|
+
gap: 12px;
|
|
164
|
+
background: none;
|
|
165
|
+
color: var(--card-fg-color);
|
|
166
|
+
|
|
167
|
+
> * {
|
|
168
|
+
@extend %card;
|
|
169
|
+
|
|
170
|
+
overflow: hidden;
|
|
171
|
+
// A row that draws a separator for its neighbours must not draw one when it
|
|
172
|
+
// IS the card (:585-586: `border: none`).
|
|
173
|
+
border-bottom: none;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/************
|
|
178
|
+
* Toolbars *
|
|
179
|
+
************/
|
|
180
|
+
|
|
181
|
+
// _toolbars.scss:91-102 + doc "Toolbars". GTK's `border-spacing: 6px` on a box
|
|
182
|
+
// is the gap between children; the flex row is what makes that expressible.
|
|
183
|
+
//
|
|
184
|
+
// The automatic flat appearance follows upstream's rule list exactly: icon-only
|
|
185
|
+
// buttons, buttons with an `adw-button-content` (icon + label), menu buttons and
|
|
186
|
+
// split buttons go flat — unless they are `.raised`, `.suggested-action`,
|
|
187
|
+
// `.destructive-action`, `.opaque`, or sit inside a `.linked` group. Text-only
|
|
188
|
+
// buttons keep their frame, which is why this cannot be a blanket
|
|
189
|
+
// `.toolbar adw-button { … }`.
|
|
190
|
+
$_keeps-frame: ':not(.raised):not(.suggested-action):not(.destructive-action):not(.opaque)';
|
|
191
|
+
|
|
192
|
+
.toolbar {
|
|
193
|
+
display: flex;
|
|
194
|
+
align-items: center;
|
|
195
|
+
gap: 6px;
|
|
196
|
+
padding: 6px;
|
|
197
|
+
|
|
198
|
+
adw-button#{$_keeps-frame} .adw-button.icon-only,
|
|
199
|
+
adw-button#{$_keeps-frame}:has(adw-button-content) .adw-button,
|
|
200
|
+
adw-menu-button#{$_keeps-frame} .adw-button,
|
|
201
|
+
adw-split-button#{$_keeps-frame} .adw-button {
|
|
202
|
+
background-color: transparent;
|
|
203
|
+
|
|
204
|
+
&:hover {
|
|
205
|
+
background-color: var(--button-hover-color);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
&:active {
|
|
209
|
+
background-color: var(--button-active-color);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Inside a linked group the frames come BACK — upstream states this as its own
|
|
214
|
+
// rule (`_toolbars.scss:20-26`) rather than as an exclusion, because a linked
|
|
215
|
+
// group only reads as one control if its members are raised.
|
|
216
|
+
.linked,
|
|
217
|
+
.adw-linked {
|
|
218
|
+
adw-button#{$_keeps-frame} .adw-button,
|
|
219
|
+
adw-menu-button#{$_keeps-frame} .adw-button,
|
|
220
|
+
adw-split-button#{$_keeps-frame} .adw-button {
|
|
221
|
+
background-color: var(--button-bg-color);
|
|
222
|
+
|
|
223
|
+
&:hover {
|
|
224
|
+
background-color: var(--button-hover-color);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
&:active {
|
|
228
|
+
background-color: var(--button-active-color);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Stand-alone OSD toolbars — the floating video-player-controls shape
|
|
234
|
+
// (:99-102).
|
|
235
|
+
&.osd {
|
|
236
|
+
padding: 12px;
|
|
237
|
+
border-radius: calc(var(--button-radius) + 6px);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// _misc.scss:21-32 — a separator that reserves whitespace instead of drawing a
|
|
242
|
+
// line, for separating groups inside a toolbar.
|
|
243
|
+
.spacer {
|
|
244
|
+
background: none;
|
|
245
|
+
border: none;
|
|
246
|
+
flex-shrink: 0;
|
|
247
|
+
|
|
248
|
+
&,
|
|
249
|
+
&.horizontal {
|
|
250
|
+
min-width: 12px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
&.vertical {
|
|
254
|
+
min-height: 12px;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/*******
|
|
259
|
+
* OSD *
|
|
260
|
+
*******/
|
|
261
|
+
|
|
262
|
+
// _common.scss:43-60. The exclusions are upstream's: a progress bar, button,
|
|
263
|
+
// menu button, split button and inline view switcher each define what `.osd`
|
|
264
|
+
// means for them, and must not get the dark surface treatment on top.
|
|
265
|
+
//
|
|
266
|
+
// This is a token REBIND, not just a colour: everything accent-coloured inside
|
|
267
|
+
// an OSD surface turns white without knowing it is inside one.
|
|
268
|
+
.osd:not(adw-progress-bar):not(adw-button):not(adw-menu-button):not(adw-split-button):not(
|
|
269
|
+
adw-inline-view-switcher
|
|
270
|
+
) {
|
|
271
|
+
--accent-bg-color: rgb(255 255 255 / 75%);
|
|
272
|
+
--accent-fg-color: rgb(0 0 0 / 75%);
|
|
273
|
+
--accent-color: oklab(from var(--accent-bg-color) max(l, 0.85) a b);
|
|
274
|
+
--destructive-color: oklab(from var(--destructive-bg-color) max(l, 0.85) a b);
|
|
275
|
+
--success-color: oklab(from var(--success-bg-color) max(l, 0.85) a b);
|
|
276
|
+
--warning-color: oklab(from var(--warning-bg-color) max(l, 0.85) a b);
|
|
277
|
+
--error-color: oklab(from var(--error-bg-color) max(l, 0.85) a b);
|
|
278
|
+
|
|
279
|
+
color: rgb(255 255 255 / 90%);
|
|
280
|
+
border: none;
|
|
281
|
+
background-color: rgb(0 0 0 / 70%);
|
|
282
|
+
background-clip: padding-box;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/*******************
|
|
286
|
+
* Linked controls *
|
|
287
|
+
*******************/
|
|
288
|
+
|
|
289
|
+
// _linked.scss:1-45 + doc "Linked Controls": the children of a linked box share
|
|
290
|
+
// their touching edges. Upstream squares the inner corners and overlaps the
|
|
291
|
+
// borders by -1px; this package's controls have no border, so the overlap is
|
|
292
|
+
// dropped and only the corner squaring remains.
|
|
293
|
+
//
|
|
294
|
+
// `.adw-linked` is this package's own earlier spelling, kept as an alias — and
|
|
295
|
+
// it USED to add a 2px gap between children, which is a segmented look, not a
|
|
296
|
+
// linked one. The gap is gone; a consumer who wanted it can say `gap`.
|
|
297
|
+
// The styled node is either the child itself (a bare `.adw-button` /
|
|
298
|
+
// `.adw-entry`) or one rendered inside the child host element (`<adw-button>`,
|
|
299
|
+
// `<adw-menu-button>`, `<adw-drop-down>`, …) — so both spellings are matched
|
|
300
|
+
// rather than enumerating host tags the way GTK has to.
|
|
301
|
+
$_linked-nodes: '.adw-button', '.adw-entry';
|
|
302
|
+
|
|
303
|
+
.linked,
|
|
304
|
+
.adw-linked {
|
|
305
|
+
display: inline-flex;
|
|
306
|
+
|
|
307
|
+
&:not(.vertical) > * {
|
|
308
|
+
@each $node in $_linked-nodes {
|
|
309
|
+
&:not(:first-child) #{$node},
|
|
310
|
+
&:not(:first-child)#{$node} {
|
|
311
|
+
border-start-start-radius: 0;
|
|
312
|
+
border-end-start-radius: 0;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
&:not(:last-child) #{$node},
|
|
316
|
+
&:not(:last-child)#{$node} {
|
|
317
|
+
border-start-end-radius: 0;
|
|
318
|
+
border-end-end-radius: 0;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
&.vertical {
|
|
324
|
+
flex-direction: column;
|
|
325
|
+
|
|
326
|
+
> * {
|
|
327
|
+
@each $node in $_linked-nodes {
|
|
328
|
+
&:not(:first-child) #{$node},
|
|
329
|
+
&:not(:first-child)#{$node} {
|
|
330
|
+
border-start-start-radius: 0;
|
|
331
|
+
border-start-end-radius: 0;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
&:not(:last-child) #{$node},
|
|
335
|
+
&:not(:last-child)#{$node} {
|
|
336
|
+
border-end-start-radius: 0;
|
|
337
|
+
border-end-end-radius: 0;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/*************
|
|
345
|
+
* App icons *
|
|
346
|
+
*************/
|
|
347
|
+
|
|
348
|
+
// _common.scss:90-104. `-gtk-icon-shadow` has no CSS counterpart; `filter:
|
|
349
|
+
// drop-shadow()` is the equivalent that follows the icon's alpha rather than its
|
|
350
|
+
// box, which is what makes these legible on a light background. Each upstream
|
|
351
|
+
// shadow layer becomes one `drop-shadow()`.
|
|
352
|
+
.lowres-icon {
|
|
353
|
+
filter: drop-shadow(0 -1px rgb(0 0 6 / 5%)) drop-shadow(1px 0 rgb(0 0 6 / 10%))
|
|
354
|
+
drop-shadow(0 1px rgb(0 0 6 / 30%)) drop-shadow(-1px 0 rgb(0 0 6 / 10%));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.icon-dropshadow {
|
|
358
|
+
filter: drop-shadow(0 1px 12px rgb(0 0 6 / 5%)) drop-shadow(0 -1px rgb(0 0 6 / 5%))
|
|
359
|
+
drop-shadow(1px 0 rgb(0 0 6 / 10%)) drop-shadow(0 1px rgb(0 0 6 / 30%))
|
|
360
|
+
drop-shadow(-1px 0 rgb(0 0 6 / 10%));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/************************
|
|
364
|
+
* Undershoot indicators *
|
|
365
|
+
************************/
|
|
366
|
+
|
|
367
|
+
// _scrolling.scss:150-166 — a shadow on the given edge of a scrolling box,
|
|
368
|
+
// telling the reader there is content past it. GTK draws them with an inset
|
|
369
|
+
// background; an inset `box-shadow` on the scroll container is the CSS
|
|
370
|
+
// equivalent and, unlike a `::before`, stays put while the content scrolls.
|
|
371
|
+
//
|
|
372
|
+
// `-start`/`-end` follow text direction, same as `margin-start`/`margin-end`,
|
|
373
|
+
// which `:dir()` expresses directly.
|
|
374
|
+
//
|
|
375
|
+
// `adw-toolbar-view` carries the same two class names for its OWN top/bottom
|
|
376
|
+
// indicators, drawn on its content node against the header shade
|
|
377
|
+
// (`_toolbar_view.scss:67-86`) — so it is excluded here rather than getting both
|
|
378
|
+
// a host shadow and a content gradient.
|
|
379
|
+
$undershoot-color: color-mix(in srgb, currentColor 6%, transparent);
|
|
380
|
+
|
|
381
|
+
.undershoot-top:not(adw-toolbar-view) {
|
|
382
|
+
box-shadow: inset 0 6px 6px -6px $undershoot-color;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.undershoot-bottom:not(adw-toolbar-view) {
|
|
386
|
+
box-shadow: inset 0 -6px 6px -6px $undershoot-color;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.undershoot-start {
|
|
390
|
+
&:dir(ltr) {
|
|
391
|
+
box-shadow: inset 6px 0 6px -6px $undershoot-color;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
&:dir(rtl) {
|
|
395
|
+
box-shadow: inset -6px 0 6px -6px $undershoot-color;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.undershoot-end {
|
|
400
|
+
&:dir(ltr) {
|
|
401
|
+
box-shadow: inset -6px 0 6px -6px $undershoot-color;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
&:dir(rtl) {
|
|
405
|
+
box-shadow: inset 6px 0 6px -6px $undershoot-color;
|
|
406
|
+
}
|
|
407
|
+
}
|
package/scss/_switch.scss
CHANGED
|
@@ -79,10 +79,11 @@
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// libadwaita dims the whole widget (`filter: Opacity(var(--disabled-opacity))`,
|
|
82
|
-
// _switch.scss:20-22)
|
|
83
|
-
//
|
|
82
|
+
// _switch.scss:20-22), and `--disabled-opacity` is a real token here now — it
|
|
83
|
+
// used to be stood in for by `--dim-opacity`, which is a different number and
|
|
84
|
+
// moves the OTHER way under high contrast.
|
|
84
85
|
.adw-switch.disabled {
|
|
85
|
-
opacity: var(--
|
|
86
|
+
opacity: var(--disabled-opacity);
|
|
86
87
|
|
|
87
88
|
.adw-switch-slider {
|
|
88
89
|
cursor: not-allowed;
|
package/scss/_theme.scss
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
5
5
|
// Modifications: Adapted for @gjsify/adwaita-web Web Components.
|
|
6
6
|
|
|
7
|
+
// `light-theme` lives in _variables.scss; @use makes it reachable (the skin uses
|
|
8
|
+
// the module system, so a mixin there is namespaced rather than global).
|
|
9
|
+
@use 'variables';
|
|
10
|
+
|
|
7
11
|
@mixin dark-theme {
|
|
8
12
|
--window-bg-color: #222226;
|
|
9
13
|
--window-fg-color: #ffffff;
|
|
@@ -64,7 +68,21 @@
|
|
|
64
68
|
}
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
// Manual override
|
|
68
|
-
|
|
71
|
+
// Manual override, on ANY element rather than only on `:root`.
|
|
72
|
+
//
|
|
73
|
+
// It was `:root.theme-dark`, which silently does nothing unless the class lands on
|
|
74
|
+
// `<html>` — so an EMBEDDED consumer could not give its own subtree a scheme without
|
|
75
|
+
// re-theming the host page around it. The storybook is exactly that case: it scopes
|
|
76
|
+
// to its own container, the class was present, the tokens never changed, and nothing
|
|
77
|
+
// reported a problem. Custom properties resolve per element, so an element-level
|
|
78
|
+
// selector overrides the inherited values for its subtree and for nothing else.
|
|
79
|
+
.theme-dark {
|
|
69
80
|
@include dark-theme;
|
|
70
81
|
}
|
|
82
|
+
|
|
83
|
+
// The light counterpart, for the same reason: on a dark system a subtree has to be
|
|
84
|
+
// able to ask for light, which `:root:not(.theme-light)` on the media query above
|
|
85
|
+
// cannot give it once the class sits anywhere but the root.
|
|
86
|
+
.theme-light {
|
|
87
|
+
@include variables.light-theme;
|
|
88
|
+
}
|
package/scss/_variables.scss
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// Copyright (c) 2025 csm (adwaita-web). MIT License.
|
|
6
6
|
// Modifications: Subset adapted for @gjsify/adwaita-web Web Components.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
@mixin light-theme {
|
|
9
9
|
// Window
|
|
10
10
|
--window-bg-color: #fafafb;
|
|
11
11
|
--window-fg-color: rgba(0, 0, 6, 0.8);
|
|
@@ -117,6 +117,21 @@
|
|
|
117
117
|
--font-size-heading: 12pt;
|
|
118
118
|
--dim-opacity: 0.55;
|
|
119
119
|
|
|
120
|
+
// Borders and disabled dimming, as libadwaita's own two-step (_colors.scss:263,
|
|
121
|
+
// 317-329): an OPACITY token the high-contrast query moves, and a colour
|
|
122
|
+
// DERIVED from it against `currentColor` — so a border follows the text colour
|
|
123
|
+
// of the surface it is drawn on instead of being a fixed grey.
|
|
124
|
+
//
|
|
125
|
+
// `--disabled-opacity` had no home here, and three partials said so in a
|
|
126
|
+
// comment and reached for `--dim-opacity` instead (`_switch.scss:81-83`,
|
|
127
|
+
// `_checks.scss:164-166`, `_progress_bar.scss:87-89`). Those are different
|
|
128
|
+
// numbers upstream — 50% disabled vs 55% dimmed — and under high contrast they
|
|
129
|
+
// move in OPPOSITE directions (disabled 40%, dimmed 90%), so the stand-in was
|
|
130
|
+
// most wrong exactly where it mattered most.
|
|
131
|
+
--border-opacity: 15%;
|
|
132
|
+
--border-color: color-mix(in srgb, currentColor var(--border-opacity), transparent);
|
|
133
|
+
--disabled-opacity: 0.5;
|
|
134
|
+
|
|
120
135
|
// Document + monospace families, behind `.document` / `.monospace`
|
|
121
136
|
// (_labels.scss:75-84). In GTK these four are written into `:root` at RUNTIME
|
|
122
137
|
// by AdwStyleManager from the desktop's font settings
|
|
@@ -134,3 +149,21 @@
|
|
|
134
149
|
--monospace-font-family: 'Adwaita Mono', ui-monospace, 'SF Mono', 'Menlo', monospace;
|
|
135
150
|
--monospace-font-size: var(--font-size-base);
|
|
136
151
|
}
|
|
152
|
+
|
|
153
|
+
// The tokens above are a MIXIN rather than a bare `:root` block so `.theme-light`
|
|
154
|
+
// can include them too (see `_theme.scss`). A light opt-out that exists only as
|
|
155
|
+
// `:not(.theme-light)` on the media query cannot serve a SUBTREE: on a dark system
|
|
156
|
+
// the root stays dark, and a container asking for light matches no rule at all.
|
|
157
|
+
:root {
|
|
158
|
+
@include light-theme;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// High contrast moves the three opacity tokens, and only those — every colour
|
|
162
|
+
// that reads them follows without its own query (_colors.scss:325-329).
|
|
163
|
+
@media (prefers-contrast: more) {
|
|
164
|
+
:root {
|
|
165
|
+
--border-opacity: 50%;
|
|
166
|
+
--dim-opacity: 0.9;
|
|
167
|
+
--disabled-opacity: 0.4;
|
|
168
|
+
}
|
|
169
|
+
}
|
package/scss/adwaita-skin.scss
CHANGED
|
@@ -25,6 +25,15 @@
|
|
|
25
25
|
// it (`_progress_bar.scss`'s text node, `_data_grid.scss`'s cells) exactly as
|
|
26
26
|
// libadwaita's own `_progress-bar.scss` does.
|
|
27
27
|
@use 'labels';
|
|
28
|
+
// The REST of libadwaita's documented style-class surface — the widget-
|
|
29
|
+
// independent half: the surfaces (`.background`, `.view`, `.frame`), `.card` and
|
|
30
|
+
// the two boxed lists, `.toolbar`, `.spacer`, `.osd`, `.linked`, the app-icon
|
|
31
|
+
// shadows and the undershoot indicators. Emitted here for the same two reasons
|
|
32
|
+
// as `_labels.scss`: a widget's own rule then wins on ordinary specificity, and
|
|
33
|
+
// `_card.scss` / `_preferences.scss` @extend `%card` from it.
|
|
34
|
+
// `scripts/check-adwaita-style-classes.mjs` holds the ledger of the whole
|
|
35
|
+
// documented surface and fails on a class with no rule behind it.
|
|
36
|
+
@use 'style_classes';
|
|
28
37
|
@use 'window';
|
|
29
38
|
@use 'headerbar';
|
|
30
39
|
@use 'window_title';
|
|
@@ -51,6 +60,9 @@
|
|
|
51
60
|
@use 'data_grid';
|
|
52
61
|
@use 'clamp';
|
|
53
62
|
@use 'spinner';
|
|
63
|
+
// <adw-shortcut-label>'s keycaps. After `labels`, because a separator inside it
|
|
64
|
+
// is an ordinary `.dimmed`.
|
|
65
|
+
@use 'shortcut_label';
|
|
54
66
|
@use 'avatar';
|
|
55
67
|
@use 'banner';
|
|
56
68
|
@use 'status_page';
|
package/src/accent.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Applying an Adwaita accent in the browser — the renderer half.
|
|
2
|
+
//
|
|
3
|
+
// The palette and the OkLab standalone derivation are `@gjsify/adwaita-core`'s
|
|
4
|
+
// (ADR 0004). This sets the two custom properties every accent-coloured rule in
|
|
5
|
+
// the stylesheet already reads:
|
|
6
|
+
//
|
|
7
|
+
// --accent-bg-color the fill, with white on top
|
|
8
|
+
// --accent-color the standalone colour, for text on the window
|
|
9
|
+
//
|
|
10
|
+
// BOTH ARE SET EXPLICITLY, from core's arithmetic, rather than setting only the
|
|
11
|
+
// background and letting CSS derive the other with
|
|
12
|
+
// `oklab(from var(--accent-bg-color) min(l, 0.5) a b)` — which is what
|
|
13
|
+
// libadwaita's own stylesheet does (`_colors.scss:166-170`). Two reasons: core is
|
|
14
|
+
// then the single source of truth for a value three renderers have to agree on,
|
|
15
|
+
// and the relative-colour form needs channel keywords inside `min()`, which is
|
|
16
|
+
// newer than this package's baseline. The CSS route stays available to a consumer
|
|
17
|
+
// who wants it; nothing here depends on it.
|
|
18
|
+
//
|
|
19
|
+
// NOTE, and it is a pre-existing inconsistency rather than something introduced
|
|
20
|
+
// here: `_variables.scss:55` hardcodes `--accent-color: #1c71d8` for the default
|
|
21
|
+
// blue, while libadwaita derives `#0461be`. The semantic colours in the same file
|
|
22
|
+
// DO use the relative-colour expression. Applying an accent through this module
|
|
23
|
+
// therefore also corrects the standalone colour; leaving it unset keeps the
|
|
24
|
+
// legacy value.
|
|
25
|
+
//
|
|
26
|
+
// Reference: refs/libadwaita/src/stylesheet/_colors.scss:146-170
|
|
27
|
+
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
28
|
+
|
|
29
|
+
import { adwaitaAccentBgColor, adwaitaAccentColor, type AdwAccentColorName } from '@gjsify/adwaita-core';
|
|
30
|
+
|
|
31
|
+
/** The custom property carrying the accent fill. */
|
|
32
|
+
export const ACCENT_BG_PROPERTY = '--accent-bg-color';
|
|
33
|
+
/** The custom property carrying the standalone accent, for text on the window. */
|
|
34
|
+
export const ACCENT_PROPERTY = '--accent-color';
|
|
35
|
+
|
|
36
|
+
/** Where and how to apply the accent. */
|
|
37
|
+
export interface ApplyAccentOptions {
|
|
38
|
+
/** The element to set the properties on. Defaults to `document.documentElement`. */
|
|
39
|
+
readonly target?: HTMLElement;
|
|
40
|
+
/**
|
|
41
|
+
* Which standalone variant to use. Defaults to the target's RESOLVED scheme,
|
|
42
|
+
* because the standalone colour is the one thing about an accent that differs
|
|
43
|
+
* between light and dark — reading it beats assuming light.
|
|
44
|
+
*/
|
|
45
|
+
readonly dark?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Whether `element` is currently rendering dark.
|
|
50
|
+
*
|
|
51
|
+
* `.theme-dark` / `.theme-light` are the stylesheet's manual overrides and win
|
|
52
|
+
* over the media query, so an explicit class is checked first and
|
|
53
|
+
* `prefers-color-scheme` only decides when neither is present.
|
|
54
|
+
*/
|
|
55
|
+
export function isAdwaitaDark(element: HTMLElement): boolean {
|
|
56
|
+
if (element.closest('.theme-dark')) return true;
|
|
57
|
+
if (element.closest('.theme-light')) return false;
|
|
58
|
+
return globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Set the accent custom properties for `name`. */
|
|
62
|
+
export function applyAdwaitaAccent(name: AdwAccentColorName, options: ApplyAccentOptions = {}): void {
|
|
63
|
+
const target = options.target ?? document.documentElement;
|
|
64
|
+
const dark = options.dark ?? isAdwaitaDark(target);
|
|
65
|
+
|
|
66
|
+
target.style.setProperty(ACCENT_BG_PROPERTY, adwaitaAccentBgColor(name));
|
|
67
|
+
target.style.setProperty(ACCENT_PROPERTY, adwaitaAccentColor(name, dark));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Drop the properties, so the stylesheet's own values apply again. */
|
|
71
|
+
export function clearAdwaitaAccent(target: HTMLElement = document.documentElement): void {
|
|
72
|
+
target.style.removeProperty(ACCENT_BG_PROPERTY);
|
|
73
|
+
target.style.removeProperty(ACCENT_PROPERTY);
|
|
74
|
+
}
|